implement missing guild alliance code

This commit is contained in:
wishu
2022-06-16 16:21:54 +10:00
parent 5563d7dc05
commit 047a18c89f
4 changed files with 193 additions and 18 deletions

20
Erupe/guild-additions.sql Normal file
View File

@@ -0,0 +1,20 @@
BEGIN;
ALTER TABLE IF EXISTS public.guilds
(
ADD COLUMN pugi_name_1 character varying(12),
ADD COLUMN pugi_name_2 character varying(12),
ADD COLUMN pugi_name_3 character varying(12)
);
CREATE TABLE IF NOT EXISTS public.guild_alliances
(
id serial NOT NULL PRIMARY KEY,
name character varying(24) NOT NULL,
created_at timestamp without time zone NOT NULL,
parent_id int NOT NULL,
sub1_id int,
sub2_id int
);
END;

View File

@@ -1,15 +1,20 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/common/bfutil"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfCreateJoint represents the MSG_MHF_CREATE_JOINT
type MsgMhfCreateJoint struct{}
type MsgMhfCreateJoint struct {
AckHandle uint32
GuildID uint32
Name string
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfCreateJoint) Opcode() network.PacketID {
@@ -18,7 +23,12 @@ func (m *MsgMhfCreateJoint) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgMhfCreateJoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
m.AckHandle = bf.ReadUint32()
m.GuildID = bf.ReadUint32()
nameLength := bf.ReadUint32()
nameBytes := bfutil.UpToNull(bf.ReadBytes(uint(nameLength)))
m.Name = ctx.StrConv.MustDecode(nameBytes)
return nil
}
// Build builds a binary packet from the current data.

View File

@@ -1,7 +1,6 @@
package channelserver
import (
"bytes"
"database/sql"
"database/sql/driver"
"encoding/binary"
@@ -9,9 +8,6 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"sort"
"strconv"
"strings"
@@ -23,8 +19,6 @@ import (
"github.com/Solenataris/Erupe/network/mhfpacket"
"github.com/jmoiron/sqlx"
"go.uber.org/zap"
"golang.org/x/text/encoding/japanese"
"golang.org/x/text/transform"
)
type FestivalColour string
@@ -764,7 +758,7 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
}
func handleRenamePugi(s *Session, data []byte, guild *Guild, num int) {
bf := NewByteFrameFromBytes(data)
bf := byteframe.NewByteFrameFromBytes(data)
_ = bf.ReadUint8() // len
_ = bf.ReadUint32() // unk
name, _ := stringsupport.ConvertSJISBytesToString(bf.ReadNullTerminatedBytes())
@@ -776,7 +770,7 @@ func handleRenamePugi(s *Session, data []byte, guild *Guild, num int) {
default:
guild.PugiName3 = name
}
guild.Save()
guild.Save(s)
}
func handleDonateRP(s *Session, pkt *mhfpacket.MsgMhfOperateGuild, bf *byteframe.ByteFrame, guild *Guild, isEvent bool) error {
@@ -1918,9 +1912,3 @@ func handleMsgMhfEnumerateInvGuild(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfOperationInvGuild(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfUpdateGuildcard(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfCreateJoint(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {}

View File

@@ -0,0 +1,157 @@
package channelserver
import (
"fmt"
"time"
"github.com/Solenataris/Erupe/network/mhfpacket"
"github.com/jmoiron/sqlx"
"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, error) {
rows, err := s.server.db.Queryx(fmt.Sprintf(`
%s
WHERE ga.id = $1
`, allianceInfoSelectQuery), AllianceID)
if err != nil {
s.logger.Error("Failed to retrieve alliance data from database", zap.Error(err))
return nil, err
}
defer rows.Close()
hasRow := rows.Next()
if !hasRow {
return nil, nil
}
return buildAllianceObjectFromDbResult(rows, err, s)
}
func buildAllianceObjectFromDbResult(result *sqlx.Rows, err error, s *Session) (*GuildAlliance, error) {
alliance := &GuildAlliance{}
err = result.StructScan(alliance)
if err != nil {
s.logger.Error("failed to retrieve alliance from database", zap.Error(err))
return nil, err
}
parentGuild, err := GetGuildInfoByID(s, alliance.ParentGuildID)
if err != nil {
s.logger.Fatal("Failed to get parent guild info", zap.Error(err))
} else {
alliance.ParentGuild = *parentGuild
alliance.TotalMembers += parentGuild.MemberCount
}
if alliance.SubGuild1ID > 0 {
subGuild1, err := GetGuildInfoByID(s, alliance.SubGuild1ID)
if err != nil {
s.logger.Fatal("Failed to get sub guild 1 info", zap.Error(err))
} else {
alliance.SubGuild1 = *subGuild1
alliance.TotalMembers += subGuild1.MemberCount
}
}
if alliance.SubGuild2ID > 0 {
subGuild2, err := GetGuildInfoByID(s, alliance.SubGuild2ID)
if err != nil {
s.logger.Fatal("Failed to get sub guild 2 info", zap.Error(err))
} else {
alliance.SubGuild2 = *subGuild2
alliance.TotalMembers += subGuild2.MemberCount
}
}
return alliance, nil
}
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.Fatal("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, err := GetGuildInfoByID(s, pkt.GuildID)
if err != nil {
s.logger.Fatal("Failed to get guild info", zap.Error(err))
}
alliance, err := GetAllianceData(s, pkt.AllianceID)
if err != nil {
s.logger.Fatal("Failed to get alliance info", zap.Error(err))
}
switch pkt.Action {
case mhfpacket.OPERATE_JOINT_DISBAND:
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.Fatal("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.OPERATE_JOINT_LEAVE:
if guild.LeaderCharID == s.charID {
// delete alliance application
// or leave alliance
} else {
s.logger.Warn(
"Non-owner of guild attempted alliance leave",
zap.Uint32("CharID", s.charID),
)
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
}
default:
panic(fmt.Sprintf("Unhandled operate joint action '%d'", pkt.Action))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
}
func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {}