Files
Erupe/server/channelserver/handlers_guild.go
Houmgaor ed2a9597f2 refactor(channelserver): extract guild model, chat commands, and seibattle
Split three large files into focused modules:
- handlers_guild.go: extract types/ORM into guild_model.go
- handlers_cast_binary.go: extract command parser into handlers_commands.go
- handlers.go: move seibattle types/handlers into handlers_seibattle.go
2026-02-18 18:24:36 +01:00

381 lines
9.7 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 {
panic(err)
}
for _, m := range mems {
bf.WriteUint32(m.CharID)
}
}
if guild.ID != alliance.SubGuild1ID {
mems, err := GetGuildMembers(s, alliance.SubGuild1ID, false)
if err != nil {
panic(err)
}
for _, m := range mems {
bf.WriteUint32(m.CharID)
}
}
if guild.ID != alliance.SubGuild2ID {
mems, err := GetGuildMembers(s, alliance.SubGuild2ID, false)
if err != nil {
panic(err)
}
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 {
panic(err)
}
characterInfo, err := GetCharacterGuildData(s, s.charID)
if err != nil {
panic(err)
}
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) {}