Files
Erupe/server/channelserver/handlers_distitem.go
Houmgaor 4e8c4b4e92 fix(channelserver): handle silently discarded errors across handlers
Replace ~17 instances of '_ =' / '_ :=' with proper error checks that
log warnings or send fail ACKs. Affected handlers: cafe, distitem, data,
guild, guild_board, guild_cooking, guild_scout, house, mercenary, misc,
and rengoku. Also resolves all pre-existing lint issues: unchecked
bf.Seek in tests, unused filtered slice in svc_festa, unused mock
fields, and unused signserver test helper.
2026-02-27 11:33:25 +01:00

185 lines
5.4 KiB
Go

package channelserver
import (
"erupe-ce/common/byteframe"
ps "erupe-ce/common/pascalstring"
cfg "erupe-ce/config"
"erupe-ce/network/mhfpacket"
"time"
"go.uber.org/zap"
)
// Distribution represents an item distribution event.
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)
bf := byteframe.NewByteFrame()
itemDists, err := s.server.distRepo.List(s.charID, pkt.DistType)
if err != nil {
s.logger.Error("Failed to list item distributions", zap.Error(err))
}
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 s.server.erupeConfig.RealClientMode >= cfg.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 s.server.erupeConfig.RealClientMode >= cfg.G7 {
bf.WriteUint8(0) // Unk
}
if s.server.erupeConfig.RealClientMode >= cfg.G6 {
bf.WriteUint16(0) // Unk
}
if s.server.erupeConfig.RealClientMode >= cfg.G8 {
if dist.Selection {
bf.WriteUint8(2) // Selection
} else {
bf.WriteUint8(0)
}
}
if s.server.erupeConfig.RealClientMode >= cfg.G7 {
bf.WriteUint16(0) // Unk
bf.WriteUint16(0) // Unk
}
if s.server.erupeConfig.RealClientMode >= cfg.G10 {
bf.WriteUint8(0) // Unk
}
ps.Uint8(bf, dist.EventName, true)
k := 6
if s.server.erupeConfig.RealClientMode >= cfg.G8 {
k = 13
}
for i := 0; i < 6; i++ {
for j := 0; j < k; j++ {
bf.WriteUint8(0)
bf.WriteUint32(0)
}
}
if s.server.erupeConfig.RealClientMode >= cfg.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())
}
// DistributionItem represents a single item in a distribution.
type DistributionItem struct {
ItemType uint8 `db:"item_type"`
ID uint32 `db:"id"`
ItemID uint32 `db:"item_id"`
Quantity uint32 `db:"quantity"`
}
func handleMsgMhfApplyDistItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfApplyDistItem)
bf := byteframe.NewByteFrame()
bf.WriteUint32(pkt.DistributionID)
distItems, err := s.server.distRepo.GetItems(pkt.DistributionID)
if err != nil {
s.logger.Error("Failed to get distribution items", zap.Error(err))
}
bf.WriteUint16(uint16(len(distItems)))
for _, item := range distItems {
bf.WriteUint8(item.ItemType)
bf.WriteUint32(item.ItemID)
bf.WriteUint32(item.Quantity)
if s.server.erupeConfig.RealClientMode >= cfg.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.distRepo.RecordAccepted(pkt.DistributionID, s.charID)
if err == nil {
distItems, err := s.server.distRepo.GetItems(pkt.DistributionID)
if err != nil {
s.logger.Error("Failed to get distribution items for acquisition", zap.Error(err))
}
for _, item := range distItems {
switch item.ItemType {
case 17:
if err := addPointNetcafe(s, int(item.Quantity)); err != nil {
s.logger.Error("Failed to add dist item netcafe points", zap.Error(err))
}
case 19:
if err := s.server.userRepo.AddPremiumCoins(s.userID, item.Quantity); err != nil {
s.logger.Error("Failed to update gacha premium", zap.Error(err))
}
case 20:
if err := s.server.userRepo.AddTrialCoins(s.userID, item.Quantity); err != nil {
s.logger.Error("Failed to update gacha trial", zap.Error(err))
}
case 21:
if err := s.server.userRepo.AddFrontierPoints(s.userID, item.Quantity); 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)
if err := saveData.Save(s); err != nil {
s.logger.Error("Failed to save RP from dist item", zap.Error(err))
}
}
}
}
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgMhfGetDistDescription(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetDistDescription)
desc, err := s.server.distRepo.GetDescription(pkt.DistributionID)
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())
}