mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 15:43:49 +01:00
Replace ~25 panic() calls in non-fatal code paths with proper s.logger.Error + return patterns. Panics in handler code crashed goroutines (caught by defer/recover but still disruptive) instead of failing gracefully. Key changes: - SJISToUTF8 now returns (string, error); all 30+ callers updated - Handler DB/IO panics replaced with log + return/ack fail - Unhandled switch-case panics replaced with logger.Error - Sign server Accept() panic replaced with log + continue - Dead unreachable panic in guild_model.go removed - deltacomp patch error logs and returns partial data Panics intentionally kept: ByteFrame sentinel, unimplemented packet stubs, os.Exit in main.go.
388 lines
10 KiB
Go
388 lines
10 KiB
Go
package channelserver
|
|
|
|
import (
|
|
"erupe-ce/common/byteframe"
|
|
"erupe-ce/common/mhfitem"
|
|
_config "erupe-ce/config"
|
|
"sort"
|
|
|
|
ps "erupe-ce/common/pascalstring"
|
|
"erupe-ce/network/mhfpacket"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func handleMsgMhfCreateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfCreateGuild)
|
|
|
|
guildId, err := CreateGuild(s, pkt.Name)
|
|
|
|
if err != nil {
|
|
bf := byteframe.NewByteFrame()
|
|
|
|
// No reasoning behind these values other than they cause a 'failed to create'
|
|
// style message, it's better than nothing for now.
|
|
bf.WriteUint32(0x01010101)
|
|
|
|
doAckSimpleFail(s, pkt.AckHandle, bf.Data())
|
|
return
|
|
}
|
|
|
|
bf := byteframe.NewByteFrame()
|
|
|
|
bf.WriteUint32(uint32(guildId))
|
|
|
|
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
|
|
}
|
|
|
|
func handleMsgMhfArrangeGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfArrangeGuildMember)
|
|
|
|
guild, err := GetGuildInfoByID(s, pkt.GuildID)
|
|
|
|
if err != nil {
|
|
s.logger.Error(
|
|
"failed to respond to ArrangeGuildMember message",
|
|
zap.Uint32("charID", s.charID),
|
|
)
|
|
return
|
|
}
|
|
|
|
if guild.LeaderCharID != s.charID {
|
|
s.logger.Error("non leader attempting to rearrange guild members!",
|
|
zap.Uint32("charID", s.charID),
|
|
zap.Uint32("guildID", guild.ID),
|
|
)
|
|
return
|
|
}
|
|
|
|
err = guild.ArrangeCharacters(s, pkt.CharIDs)
|
|
|
|
if err != nil {
|
|
s.logger.Error(
|
|
"failed to respond to ArrangeGuildMember message",
|
|
zap.Uint32("charID", s.charID),
|
|
zap.Uint32("guildID", guild.ID),
|
|
)
|
|
return
|
|
}
|
|
|
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
|
}
|
|
|
|
func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfEnumerateGuildMember)
|
|
|
|
var guild *Guild
|
|
var err error
|
|
|
|
if pkt.GuildID > 0 {
|
|
guild, err = GetGuildInfoByID(s, pkt.GuildID)
|
|
} else {
|
|
guild, err = GetGuildInfoByCharacterId(s, s.charID)
|
|
}
|
|
|
|
if guild != nil {
|
|
isApplicant, _ := guild.HasApplicationForCharID(s, s.charID)
|
|
if isApplicant {
|
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2))
|
|
return
|
|
}
|
|
}
|
|
|
|
if guild == nil && s.prevGuildID > 0 {
|
|
guild, err = GetGuildInfoByID(s, s.prevGuildID)
|
|
}
|
|
|
|
if err != nil {
|
|
s.logger.Warn("failed to retrieve guild sending no result message")
|
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2))
|
|
return
|
|
} else if guild == nil {
|
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2))
|
|
return
|
|
}
|
|
|
|
guildMembers, err := GetGuildMembers(s, guild.ID, false)
|
|
|
|
if err != nil {
|
|
s.logger.Error("failed to retrieve guild")
|
|
return
|
|
}
|
|
|
|
alliance, err := GetAllianceData(s, guild.AllianceID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get alliance data")
|
|
return
|
|
}
|
|
|
|
bf := byteframe.NewByteFrame()
|
|
|
|
bf.WriteUint16(uint16(len(guildMembers)))
|
|
|
|
sort.Slice(guildMembers[:], func(i, j int) bool {
|
|
return guildMembers[i].OrderIndex < guildMembers[j].OrderIndex
|
|
})
|
|
|
|
for _, member := range guildMembers {
|
|
bf.WriteUint32(member.CharID)
|
|
bf.WriteUint16(member.HR)
|
|
if s.server.erupeConfig.RealClientMode >= _config.G10 {
|
|
bf.WriteUint16(member.GR)
|
|
}
|
|
if s.server.erupeConfig.RealClientMode < _config.ZZ {
|
|
// Magnet Spike crash workaround
|
|
bf.WriteUint16(0)
|
|
} else {
|
|
bf.WriteUint16(member.WeaponID)
|
|
}
|
|
if member.WeaponType == 1 || member.WeaponType == 5 || member.WeaponType == 10 { // If weapon is ranged
|
|
bf.WriteUint8(7)
|
|
} else {
|
|
bf.WriteUint8(6)
|
|
}
|
|
bf.WriteUint16(member.OrderIndex)
|
|
bf.WriteBool(member.AvoidLeadership)
|
|
ps.Uint8(bf, member.Name, true)
|
|
}
|
|
|
|
for _, member := range guildMembers {
|
|
bf.WriteUint32(member.LastLogin)
|
|
}
|
|
|
|
if guild.AllianceID > 0 {
|
|
bf.WriteUint16(alliance.TotalMembers - uint16(len(guildMembers)))
|
|
if guild.ID != alliance.ParentGuildID {
|
|
mems, err := GetGuildMembers(s, alliance.ParentGuildID, false)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get parent guild members for alliance", zap.Error(err))
|
|
return
|
|
}
|
|
for _, m := range mems {
|
|
bf.WriteUint32(m.CharID)
|
|
}
|
|
}
|
|
if guild.ID != alliance.SubGuild1ID {
|
|
mems, err := GetGuildMembers(s, alliance.SubGuild1ID, false)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get sub guild 1 members for alliance", zap.Error(err))
|
|
return
|
|
}
|
|
for _, m := range mems {
|
|
bf.WriteUint32(m.CharID)
|
|
}
|
|
}
|
|
if guild.ID != alliance.SubGuild2ID {
|
|
mems, err := GetGuildMembers(s, alliance.SubGuild2ID, false)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get sub guild 2 members for alliance", zap.Error(err))
|
|
return
|
|
}
|
|
for _, m := range mems {
|
|
bf.WriteUint32(m.CharID)
|
|
}
|
|
}
|
|
} else {
|
|
bf.WriteUint16(0)
|
|
}
|
|
|
|
for _, member := range guildMembers {
|
|
bf.WriteUint16(member.RPToday)
|
|
bf.WriteUint16(member.RPYesterday)
|
|
}
|
|
|
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
|
}
|
|
|
|
func handleMsgMhfGetGuildManageRight(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfGetGuildManageRight)
|
|
|
|
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
|
if guild == nil || s.prevGuildID != 0 {
|
|
guild, err := GetGuildInfoByID(s, s.prevGuildID)
|
|
s.prevGuildID = 0
|
|
if guild == nil || err != nil {
|
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
|
return
|
|
}
|
|
}
|
|
|
|
bf := byteframe.NewByteFrame()
|
|
bf.WriteUint32(uint32(guild.MemberCount))
|
|
members, _ := GetGuildMembers(s, guild.ID, false)
|
|
for _, member := range members {
|
|
bf.WriteUint32(member.CharID)
|
|
bf.WriteBool(member.Recruiter)
|
|
bf.WriteBytes(make([]byte, 3))
|
|
}
|
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
|
}
|
|
|
|
func handleMsgMhfGetUdGuildMapInfo(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfGetUdGuildMapInfo)
|
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
|
}
|
|
|
|
func handleMsgMhfGetGuildTargetMemberNum(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfGetGuildTargetMemberNum)
|
|
|
|
var guild *Guild
|
|
var err error
|
|
|
|
if pkt.GuildID == 0x0 {
|
|
guild, err = GetGuildInfoByCharacterId(s, s.charID)
|
|
} else {
|
|
guild, err = GetGuildInfoByID(s, pkt.GuildID)
|
|
}
|
|
|
|
if err != nil || guild == nil {
|
|
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x02})
|
|
return
|
|
}
|
|
|
|
bf := byteframe.NewByteFrame()
|
|
|
|
bf.WriteUint16(0x0)
|
|
bf.WriteUint16(guild.MemberCount - 1)
|
|
|
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
|
}
|
|
|
|
func handleMsgMhfEnumerateGuildItem(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfEnumerateGuildItem)
|
|
items := guildGetItems(s, pkt.GuildID)
|
|
bf := byteframe.NewByteFrame()
|
|
bf.WriteBytes(mhfitem.SerializeWarehouseItems(items))
|
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
|
}
|
|
|
|
func handleMsgMhfUpdateGuildItem(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfUpdateGuildItem)
|
|
newStacks := mhfitem.DiffItemStacks(guildGetItems(s, pkt.GuildID), pkt.UpdatedItems)
|
|
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))
|
|
}
|
|
|
|
func handleMsgMhfUpdateGuildIcon(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfUpdateGuildIcon)
|
|
|
|
guild, err := GetGuildInfoByID(s, pkt.GuildID)
|
|
|
|
if err != nil {
|
|
s.logger.Error("Failed to get guild info for icon update", zap.Error(err))
|
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
|
return
|
|
}
|
|
|
|
characterInfo, err := GetCharacterGuildData(s, s.charID)
|
|
|
|
if err != nil {
|
|
s.logger.Error("Failed to get character guild data for icon update", zap.Error(err))
|
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
|
return
|
|
}
|
|
|
|
if !characterInfo.IsSubLeader() && !characterInfo.IsLeader {
|
|
s.logger.Warn(
|
|
"character without leadership attempting to update guild icon",
|
|
zap.Uint32("guildID", guild.ID),
|
|
zap.Uint32("charID", s.charID),
|
|
)
|
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
|
return
|
|
}
|
|
|
|
icon := &GuildIcon{}
|
|
|
|
icon.Parts = make([]GuildIconPart, len(pkt.IconParts))
|
|
|
|
for i, p := range pkt.IconParts {
|
|
icon.Parts[i] = GuildIconPart{
|
|
Index: p.Index,
|
|
ID: p.ID,
|
|
Page: p.Page,
|
|
Size: p.Size,
|
|
Rotation: p.Rotation,
|
|
Red: p.Red,
|
|
Green: p.Green,
|
|
Blue: p.Blue,
|
|
PosX: p.PosX,
|
|
PosY: p.PosY,
|
|
}
|
|
}
|
|
|
|
guild.Icon = icon
|
|
|
|
err = guild.Save(s)
|
|
|
|
if err != nil {
|
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
|
return
|
|
}
|
|
|
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
|
}
|
|
|
|
func handleMsgMhfReadGuildcard(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfReadGuildcard)
|
|
|
|
resp := byteframe.NewByteFrame()
|
|
resp.WriteUint32(0)
|
|
resp.WriteUint32(0)
|
|
resp.WriteUint32(0)
|
|
resp.WriteUint32(0)
|
|
resp.WriteUint32(0)
|
|
resp.WriteUint32(0)
|
|
resp.WriteUint32(0)
|
|
resp.WriteUint32(0)
|
|
|
|
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
|
}
|
|
|
|
func handleMsgMhfEntryRookieGuild(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfEntryRookieGuild)
|
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
|
}
|
|
|
|
func handleMsgMhfUpdateForceGuildRank(s *Session, p mhfpacket.MHFPacket) {}
|
|
|
|
func handleMsgMhfGenerateUdGuildMap(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfGenerateUdGuildMap)
|
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
|
}
|
|
|
|
func handleMsgMhfUpdateGuild(s *Session, p mhfpacket.MHFPacket) {}
|
|
|
|
func handleMsgMhfSetGuildManageRight(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfSetGuildManageRight)
|
|
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))
|
|
}
|
|
|
|
func handleMsgMhfCheckMonthlyItem(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfCheckMonthlyItem)
|
|
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01})
|
|
// TODO: Implement month-by-month tracker, 0 = Not claimed, 1 = Claimed
|
|
// Also handles HLC and EXC items, IDs = 064D, 076B
|
|
}
|
|
|
|
func handleMsgMhfAcquireMonthlyItem(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfAcquireMonthlyItem)
|
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
|
}
|
|
|
|
func handleMsgMhfEnumerateInvGuild(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfEnumerateInvGuild)
|
|
stubEnumerateNoResults(s, pkt.AckHandle)
|
|
}
|
|
|
|
func handleMsgMhfOperationInvGuild(s *Session, p mhfpacket.MHFPacket) {
|
|
pkt := p.(*mhfpacket.MsgMhfOperationInvGuild)
|
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
|
}
|
|
|
|
func handleMsgMhfUpdateGuildcard(s *Session, p mhfpacket.MHFPacket) {}
|