mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 15:43:49 +01:00
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.
211 lines
6.6 KiB
Go
211 lines
6.6 KiB
Go
package channelserver
|
|
|
|
import (
|
|
"erupe-ce/common/byteframe"
|
|
ps "erupe-ce/common/pascalstring"
|
|
_config "erupe-ce/config"
|
|
"erupe-ce/network/mhfpacket"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type Distribution struct {
|
|
ID uint32 `db:"id"`
|
|
Deadline time.Time `db:"deadline"`
|
|
Rights uint32 `db:"rights"`
|
|
TimesAcceptable uint16 `db:"times_acceptable"`
|
|
TimesAccepted uint16 `db:"times_accepted"`
|
|
MinHR int16 `db:"min_hr"`
|
|
MaxHR int16 `db:"max_hr"`
|
|
MinSR int16 `db:"min_sr"`
|
|
MaxSR int16 `db:"max_sr"`
|
|
MinGR int16 `db:"min_gr"`
|
|
MaxGR int16 `db:"max_gr"`
|
|
EventName string `db:"event_name"`
|
|
Description string `db:"description"`
|
|
Selection bool `db:"selection"`
|
|
}
|
|
|
|
func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfEnumerateDistItem)
|
|
|
|
var itemDists []Distribution
|
|
bf := byteframe.NewByteFrame()
|
|
rows, err := s.server.db.Queryx(`
|
|
SELECT d.id, event_name, description, COALESCE(rights, 0) AS rights, COALESCE(selection, false) AS selection, times_acceptable,
|
|
COALESCE(min_hr, -1) AS min_hr, COALESCE(max_hr, -1) AS max_hr,
|
|
COALESCE(min_sr, -1) AS min_sr, COALESCE(max_sr, -1) AS max_sr,
|
|
COALESCE(min_gr, -1) AS min_gr, COALESCE(max_gr, -1) AS max_gr,
|
|
(
|
|
SELECT count(*) FROM distributions_accepted da
|
|
WHERE d.id = da.distribution_id AND da.character_id = $1
|
|
) AS times_accepted,
|
|
COALESCE(deadline, TO_TIMESTAMP(0)) AS deadline
|
|
FROM distribution d
|
|
WHERE character_id = $1 AND type = $2 OR character_id IS NULL AND type = $2 ORDER BY id DESC
|
|
`, s.charID, pkt.DistType)
|
|
|
|
if err == nil {
|
|
var itemDist Distribution
|
|
for rows.Next() {
|
|
err = rows.StructScan(&itemDist)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
itemDists = append(itemDists, itemDist)
|
|
}
|
|
}
|
|
|
|
bf.WriteUint16(uint16(len(itemDists)))
|
|
for _, dist := range itemDists {
|
|
bf.WriteUint32(dist.ID)
|
|
bf.WriteUint32(uint32(dist.Deadline.Unix()))
|
|
bf.WriteUint32(dist.Rights)
|
|
bf.WriteUint16(dist.TimesAcceptable)
|
|
bf.WriteUint16(dist.TimesAccepted)
|
|
if _config.ErupeConfig.RealClientMode >= _config.G9 {
|
|
bf.WriteUint16(0) // Unk
|
|
}
|
|
bf.WriteInt16(dist.MinHR)
|
|
bf.WriteInt16(dist.MaxHR)
|
|
bf.WriteInt16(dist.MinSR)
|
|
bf.WriteInt16(dist.MaxSR)
|
|
bf.WriteInt16(dist.MinGR)
|
|
bf.WriteInt16(dist.MaxGR)
|
|
if _config.ErupeConfig.RealClientMode >= _config.G7 {
|
|
bf.WriteUint8(0) // Unk
|
|
}
|
|
if _config.ErupeConfig.RealClientMode >= _config.G6 {
|
|
bf.WriteUint16(0) // Unk
|
|
}
|
|
if _config.ErupeConfig.RealClientMode >= _config.G8 {
|
|
if dist.Selection {
|
|
bf.WriteUint8(2) // Selection
|
|
} else {
|
|
bf.WriteUint8(0)
|
|
}
|
|
}
|
|
if _config.ErupeConfig.RealClientMode >= _config.G7 {
|
|
bf.WriteUint16(0) // Unk
|
|
bf.WriteUint16(0) // Unk
|
|
}
|
|
if _config.ErupeConfig.RealClientMode >= _config.G10 {
|
|
bf.WriteUint8(0) // Unk
|
|
}
|
|
ps.Uint8(bf, dist.EventName, true)
|
|
k := 6
|
|
if _config.ErupeConfig.RealClientMode >= _config.G8 {
|
|
k = 13
|
|
}
|
|
for i := 0; i < 6; i++ {
|
|
for j := 0; j < k; j++ {
|
|
bf.WriteUint8(0)
|
|
bf.WriteUint32(0)
|
|
}
|
|
}
|
|
if _config.ErupeConfig.RealClientMode >= _config.Z2 {
|
|
i := uint8(0)
|
|
bf.WriteUint8(i)
|
|
if i <= 10 {
|
|
for j := uint8(0); j < i; j++ {
|
|
bf.WriteUint32(0)
|
|
bf.WriteUint32(0)
|
|
bf.WriteUint32(0)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
|
}
|
|
|
|
type DistributionItem struct {
|
|
ItemType uint8 `db:"item_type"`
|
|
ID uint32 `db:"id"`
|
|
ItemID uint32 `db:"item_id"`
|
|
Quantity uint32 `db:"quantity"`
|
|
}
|
|
|
|
func getDistributionItems(s *Session, i uint32) []DistributionItem {
|
|
var distItems []DistributionItem
|
|
rows, err := s.server.db.Queryx(`SELECT id, item_type, COALESCE(item_id, 0) AS item_id, COALESCE(quantity, 0) AS quantity FROM distribution_items WHERE distribution_id=$1`, i)
|
|
if err == nil {
|
|
var distItem DistributionItem
|
|
for rows.Next() {
|
|
err = rows.StructScan(&distItem)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
distItems = append(distItems, distItem)
|
|
}
|
|
}
|
|
return distItems
|
|
}
|
|
|
|
func handleMsgMhfApplyDistItem(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfApplyDistItem)
|
|
bf := byteframe.NewByteFrame()
|
|
bf.WriteUint32(pkt.DistributionID)
|
|
distItems := getDistributionItems(s, pkt.DistributionID)
|
|
bf.WriteUint16(uint16(len(distItems)))
|
|
for _, item := range distItems {
|
|
bf.WriteUint8(item.ItemType)
|
|
bf.WriteUint32(item.ItemID)
|
|
bf.WriteUint32(item.Quantity)
|
|
if _config.ErupeConfig.RealClientMode >= _config.G8 {
|
|
bf.WriteUint32(item.ID)
|
|
}
|
|
}
|
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
|
}
|
|
|
|
func handleMsgMhfAcquireDistItem(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfAcquireDistItem)
|
|
if pkt.DistributionID > 0 {
|
|
_, err := s.server.db.Exec(`INSERT INTO public.distributions_accepted VALUES ($1, $2)`, pkt.DistributionID, s.charID)
|
|
if err == nil {
|
|
distItems := getDistributionItems(s, pkt.DistributionID)
|
|
for _, item := range distItems {
|
|
switch item.ItemType {
|
|
case 17:
|
|
_ = addPointNetcafe(s, int(item.Quantity))
|
|
case 19:
|
|
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:
|
|
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:
|
|
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 {
|
|
saveData.RP += uint16(item.Quantity)
|
|
saveData.Save(s)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
|
}
|
|
|
|
func handleMsgMhfGetDistDescription(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfGetDistDescription)
|
|
var desc string
|
|
err := s.server.db.QueryRow("SELECT description FROM distribution WHERE id = $1", pkt.DistributionID).Scan(&desc)
|
|
if err != nil {
|
|
s.logger.Error("Error parsing item distribution description", zap.Error(err))
|
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
|
return
|
|
}
|
|
bf := byteframe.NewByteFrame()
|
|
ps.Uint16(bf, desc, true)
|
|
ps.Uint16(bf, "", false)
|
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
|
}
|