mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 15:43:49 +01:00
Several handler files discarded errors from repository and service calls, creating nil-dereference risks and silent data corruption: - guild_adventure: 3 GetByCharID calls could panic on nil guild - gacha: GetGachaPoints silently returned zero balances on DB error - house: HasApplication called before nil check on guild; GetHouseContents error discarded with 7 return values - distitem: 3 distRepo calls had no error logging - guild_ops: Disband/Leave service errors were invisible - shop: gacha type/weight/fpoint lookups had no error logging - discord: bcrypt error could result in nil password being set
181 lines
5.2 KiB
Go
181 lines
5.2 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:
|
|
_ = addPointNetcafe(s, int(item.Quantity))
|
|
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)
|
|
saveData.Save(s)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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())
|
|
}
|