Files
Erupe/server/channelserver/handlers_guild_alliance.go
2024-08-21 21:04:52 +10:00

203 lines
6.3 KiB
Go

package channelserver
import (
"erupe-ce/common/byteframe"
ps "erupe-ce/common/pascalstring"
"fmt"
"time"
"erupe-ce/network/mhfpacket"
"go.uber.org/zap"
)
const allianceInfoSelectQuery = `
SELECT
ga.id,
ga.name,
created_at,
parent_id,
CASE
WHEN sub1_id IS NULL THEN 0
ELSE sub1_id
END,
CASE
WHEN sub2_id IS NULL THEN 0
ELSE sub2_id
END
FROM guild_alliances ga
`
type GuildAlliance struct {
ID uint32 `db:"id"`
Name string `db:"name"`
CreatedAt time.Time `db:"created_at"`
TotalMembers uint16
ParentGuildID uint32 `db:"parent_id"`
SubGuild1ID uint32 `db:"sub1_id"`
SubGuild2ID uint32 `db:"sub2_id"`
ParentGuild Guild
SubGuild1 Guild
SubGuild2 Guild
}
func GetAllianceData(s *Session, AllianceID uint32) GuildAlliance {
var alliance GuildAlliance
err := s.server.db.QueryRowx(fmt.Sprintf(`
%s
WHERE ga.id = $1
`, allianceInfoSelectQuery), AllianceID).StructScan(&alliance)
if err != nil {
s.logger.Error("failed to retrieve alliance data", zap.Error(err))
} else {
parentGuild := GetGuildInfoByID(s, alliance.ParentGuildID)
if parentGuild.ID > 0 {
alliance.ParentGuild = parentGuild
alliance.TotalMembers += parentGuild.MemberCount
}
if alliance.SubGuild1ID > 0 {
subGuild1 := GetGuildInfoByID(s, alliance.SubGuild1ID)
if subGuild1.ID > 0 {
alliance.SubGuild1 = subGuild1
alliance.TotalMembers += subGuild1.MemberCount
}
}
if alliance.SubGuild2ID > 0 {
subGuild2 := GetGuildInfoByID(s, alliance.SubGuild2ID)
if subGuild2.ID > 0 {
alliance.SubGuild2 = subGuild2
alliance.TotalMembers += subGuild2.MemberCount
}
}
}
return alliance
}
func handleMsgMhfCreateJoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfCreateJoint)
_, err := s.server.db.Exec("INSERT INTO guild_alliances (name, parent_id) VALUES ($1, $2)", pkt.Name, pkt.GuildID)
if err != nil {
s.logger.Error("Failed to create guild alliance in db", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x01, 0x01, 0x01, 0x01})
}
func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfOperateJoint)
guild := GetGuildInfoByID(s, pkt.GuildID)
if guild.ID == 0 {
s.logger.Error("failed to get guild info")
}
alliance := GetAllianceData(s, pkt.AllianceID)
if alliance.ID == 0 {
s.logger.Error("failed to get alliance info")
}
switch pkt.Action {
case mhfpacket.OperateJointDisband:
if guild.LeaderCharID == s.charID && alliance.ParentGuildID == guild.ID {
_, err := s.server.db.Exec("DELETE FROM guild_alliances WHERE id=$1", alliance.ID)
if err != nil {
s.logger.Error("Failed to disband alliance", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} else {
s.logger.Warn(
"Non-owner of alliance attempted disband",
zap.Uint32("CharID", s.charID),
zap.Uint32("AllyID", alliance.ID),
)
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
}
case mhfpacket.OperateJointLeave:
if guild.LeaderCharID == s.charID {
if guild.ID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 {
s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID)
} else if guild.ID == alliance.SubGuild1ID && alliance.SubGuild2ID == 0 {
s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID)
} else {
s.server.db.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID)
}
// TODO: Handle deleting Alliance applications
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} else {
s.logger.Warn(
"Non-owner of guild attempted alliance leave",
zap.Uint32("CharID", s.charID),
)
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
}
case mhfpacket.OperateJointKick:
if alliance.ParentGuild.LeaderCharID == s.charID {
kickedGuildID := pkt.Data1.ReadUint32()
if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 {
s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID)
} else if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID == 0 {
s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID)
} else {
s.server.db.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID)
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} else {
s.logger.Warn(
"Non-owner of alliance attempted kick",
zap.Uint32("CharID", s.charID),
zap.Uint32("AllyID", alliance.ID),
)
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
}
default:
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
panic(fmt.Sprintf("Unhandled operate joint action '%d'", pkt.Action))
}
}
func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfInfoJoint)
bf := byteframe.NewByteFrame()
alliance := GetAllianceData(s, pkt.AllianceID)
if alliance.ID == 0 {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
} else {
bf.WriteUint32(alliance.ID)
bf.WriteUint32(uint32(alliance.CreatedAt.Unix()))
bf.WriteUint16(alliance.TotalMembers)
bf.WriteUint16(0x0000) // Unk
ps.Uint16(bf, alliance.Name, true)
if alliance.SubGuild1ID > 0 {
if alliance.SubGuild2ID > 0 {
bf.WriteUint8(3)
} else {
bf.WriteUint8(2)
}
} else {
bf.WriteUint8(1)
}
bf.WriteUint32(alliance.ParentGuildID)
bf.WriteUint32(alliance.ParentGuild.LeaderCharID)
bf.WriteUint16(alliance.ParentGuild.Rank())
bf.WriteUint16(alliance.ParentGuild.MemberCount)
ps.Uint16(bf, alliance.ParentGuild.Name, true)
ps.Uint16(bf, alliance.ParentGuild.LeaderName, true)
if alliance.SubGuild1ID > 0 {
bf.WriteUint32(alliance.SubGuild1ID)
bf.WriteUint32(alliance.SubGuild1.LeaderCharID)
bf.WriteUint16(alliance.SubGuild1.Rank())
bf.WriteUint16(alliance.SubGuild1.MemberCount)
ps.Uint16(bf, alliance.SubGuild1.Name, true)
ps.Uint16(bf, alliance.SubGuild1.LeaderName, true)
}
if alliance.SubGuild2ID > 0 {
bf.WriteUint32(alliance.SubGuild2ID)
bf.WriteUint32(alliance.SubGuild2.LeaderCharID)
bf.WriteUint16(alliance.SubGuild2.Rank())
bf.WriteUint16(alliance.SubGuild2.MemberCount)
ps.Uint16(bf, alliance.SubGuild2.Name, true)
ps.Uint16(bf, alliance.SubGuild2.LeaderName, true)
}
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
}