mirror of
https://github.com/Mezeporta/Erupe.git
synced 2025-12-13 15:34:38 +01:00
Compare commits
7 Commits
fix/clan-i
...
feature/hu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e412592745 | ||
|
|
94e0f20682 | ||
|
|
79dce0bc52 | ||
|
|
4c485ef55a | ||
|
|
fe1052a517 | ||
|
|
687ad05172 | ||
|
|
38f4399cab |
@@ -29,23 +29,6 @@ func SJISToUTF8(b []byte) string {
|
|||||||
return string(result)
|
return string(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToNGWord(x string) []uint16 {
|
|
||||||
var w []uint16
|
|
||||||
for _, r := range []rune(x) {
|
|
||||||
if r > 0xFF {
|
|
||||||
t := UTF8ToSJIS(string(r))
|
|
||||||
if len(t) > 1 {
|
|
||||||
w = append(w, uint16(t[1])<<8|uint16(t[0]))
|
|
||||||
} else {
|
|
||||||
w = append(w, uint16(t[0]))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
w = append(w, uint16(r))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
func PaddedString(x string, size uint, t bool) []byte {
|
func PaddedString(x string, size uint, t bool) []byte {
|
||||||
if t {
|
if t {
|
||||||
e := japanese.ShiftJIS.NewEncoder()
|
e := japanese.ShiftJIS.NewEncoder()
|
||||||
|
|||||||
@@ -10,19 +10,20 @@ import (
|
|||||||
type EnumerateGuildType uint8
|
type EnumerateGuildType uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
EnumerateGuildTypeGuildName = iota + 1
|
ENUMERATE_GUILD_UNKNOWN = iota
|
||||||
EnumerateGuildTypeLeaderName
|
ENUMERATE_GUILD_TYPE_GUILD_NAME
|
||||||
EnumerateGuildTypeLeaderId
|
ENUMERATE_GUILD_TYPE_LEADER_NAME
|
||||||
EnumerateGuildTypeOrderMembers
|
ENUMERATE_GUILD_TYPE_LEADER_ID
|
||||||
EnumerateGuildTypeOrderRegistration
|
ENUMERATE_GUILD_TYPE_ORDER_MEMBERS
|
||||||
EnumerateGuildTypeOrderRank
|
ENUMERATE_GUILD_TYPE_ORDER_REGISTRATION
|
||||||
EnumerateGuildTypeMotto
|
ENUMERATE_GUILD_TYPE_ORDER_RANK
|
||||||
EnumerateGuildTypeRecruiting
|
ENUMERATE_GUILD_TYPE_MOTTO
|
||||||
EnumerateAllianceTypeAllianceName
|
ENUMERATE_GUILD_TYPE_RECRUITING
|
||||||
EnumerateAllianceTypeLeaderName
|
ENUMERATE_ALLIANCE_TYPE_ALLIANCE_NAME
|
||||||
EnumerateAllianceTypeLeaderId
|
ENUMERATE_ALLIANCE_TYPE_LEADER_NAME
|
||||||
EnumerateAllianceTypeOrderMembers
|
ENUMERATE_ALLIANCE_TYPE_LEADER_ID
|
||||||
EnumerateAllianceTypeOrderRegistration
|
ENUMERATE_ALLIANCE_TYPE_ORDER_MEMBERS
|
||||||
|
ENUMERATE_ALLIANCE_TYPE_ORDER_REGISTRATION
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfEnumerateGuild represents the MSG_MHF_ENUMERATE_GUILD
|
// MsgMhfEnumerateGuild represents the MSG_MHF_ENUMERATE_GUILD
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import (
|
|||||||
type MsgMhfEnumerateInvGuild struct {
|
type MsgMhfEnumerateInvGuild struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk uint32
|
Unk uint32
|
||||||
ActiveHours1 uint8
|
Operation uint8
|
||||||
ActiveHours2 uint8
|
ActiveHours uint8
|
||||||
DaysActive uint8
|
DaysActive uint8
|
||||||
PlayStyle uint8
|
PlayStyle uint8
|
||||||
GuildRequest uint8
|
GuildRequest uint8
|
||||||
@@ -28,8 +28,8 @@ func (m *MsgMhfEnumerateInvGuild) Opcode() network.PacketID {
|
|||||||
func (m *MsgMhfEnumerateInvGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfEnumerateInvGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk = bf.ReadUint32()
|
m.Unk = bf.ReadUint32()
|
||||||
m.ActiveHours1 = bf.ReadUint8()
|
m.Operation = bf.ReadUint8()
|
||||||
m.ActiveHours2 = bf.ReadUint8()
|
m.ActiveHours = bf.ReadUint8()
|
||||||
m.DaysActive = bf.ReadUint8()
|
m.DaysActive = bf.ReadUint8()
|
||||||
m.PlayStyle = bf.ReadUint8()
|
m.PlayStyle = bf.ReadUint8()
|
||||||
m.GuildRequest = bf.ReadUint8()
|
m.GuildRequest = bf.ReadUint8()
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfEnumerateOrder represents the MSG_MHF_ENUMERATE_ORDER
|
// MsgMhfEnumerateOrder represents the MSG_MHF_ENUMERATE_ORDER
|
||||||
type MsgMhfEnumerateOrder struct {
|
type MsgMhfEnumerateOrder struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk0 uint32
|
EventID uint32
|
||||||
Unk1 uint32
|
ClanID uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// Opcode returns the ID associated with this packet type.
|
||||||
@@ -23,8 +23,8 @@ func (m *MsgMhfEnumerateOrder) Opcode() network.PacketID {
|
|||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfEnumerateOrder) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfEnumerateOrder) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint32()
|
m.EventID = bf.ReadUint32()
|
||||||
m.Unk1 = bf.ReadUint32()
|
m.ClanID = bf.ReadUint32()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ import (
|
|||||||
type OperateGuildMemberAction uint8
|
type OperateGuildMemberAction uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OperateGuildMemberAccept = iota + 1
|
_ = iota
|
||||||
OperateGuildMemberReject
|
OPERATE_GUILD_MEMBER_ACTION_ACCEPT
|
||||||
OperateGuildMemberKick
|
OPERATE_GUILD_MEMBER_ACTION_REJECT
|
||||||
|
OPERATE_GUILD_MEMBER_ACTION_KICK
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfOperateGuildMember represents the MSG_MHF_OPERATE_GUILD_MEMBER
|
// MsgMhfOperateGuildMember represents the MSG_MHF_OPERATE_GUILD_MEMBER
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import (
|
|||||||
type OperateJointAction uint8
|
type OperateJointAction uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OperateJointDisband = 1
|
OPERATE_JOINT_DISBAND = 0x01
|
||||||
OperateJointLeave = 3
|
OPERATE_JOINT_LEAVE = 0x03
|
||||||
OperateJointKick = 9
|
OPERATE_JOINT_KICK = 0x09
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfOperateJoint represents the MSG_MHF_OPERATE_JOINT
|
// MsgMhfOperateJoint represents the MSG_MHF_OPERATE_JOINT
|
||||||
|
|||||||
@@ -8,17 +8,10 @@ import (
|
|||||||
"erupe-ce/network/clientctx"
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OperateInvGuildAction uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
OperateInvGuildSend = iota + 1
|
|
||||||
OperateInvGuildCancel
|
|
||||||
)
|
|
||||||
|
|
||||||
// MsgMhfOperationInvGuild represents the MSG_MHF_OPERATION_INV_GUILD
|
// MsgMhfOperationInvGuild represents the MSG_MHF_OPERATION_INV_GUILD
|
||||||
type MsgMhfOperationInvGuild struct {
|
type MsgMhfOperationInvGuild struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Action uint8
|
Operation uint8
|
||||||
ActiveHours uint8
|
ActiveHours uint8
|
||||||
DaysActive uint8
|
DaysActive uint8
|
||||||
PlayStyle uint8
|
PlayStyle uint8
|
||||||
@@ -33,7 +26,7 @@ func (m *MsgMhfOperationInvGuild) Opcode() network.PacketID {
|
|||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfOperationInvGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfOperationInvGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Action = bf.ReadUint8()
|
m.Operation = bf.ReadUint8()
|
||||||
m.ActiveHours = bf.ReadUint8()
|
m.ActiveHours = bf.ReadUint8()
|
||||||
m.DaysActive = bf.ReadUint8()
|
m.DaysActive = bf.ReadUint8()
|
||||||
m.PlayStyle = bf.ReadUint8()
|
m.PlayStyle = bf.ReadUint8()
|
||||||
|
|||||||
@@ -37,16 +37,13 @@ func (m *MsgMhfStampcardStamp) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli
|
|||||||
}
|
}
|
||||||
m.Stamps = bf.ReadUint16()
|
m.Stamps = bf.ReadUint16()
|
||||||
bf.ReadUint16() // Zeroed
|
bf.ReadUint16() // Zeroed
|
||||||
if _config.ErupeConfig.RealClientMode >= _config.Z2 {
|
if _config.ErupeConfig.RealClientMode > _config.Z1 {
|
||||||
m.Reward1 = uint16(bf.ReadUint32())
|
m.Reward1 = uint16(bf.ReadUint32())
|
||||||
m.Reward2 = uint16(bf.ReadUint32())
|
m.Reward2 = uint16(bf.ReadUint32())
|
||||||
m.Item1 = uint16(bf.ReadUint32())
|
m.Item1 = uint16(bf.ReadUint32())
|
||||||
m.Item2 = uint16(bf.ReadUint32())
|
m.Item2 = uint16(bf.ReadUint32())
|
||||||
m.Quantity1 = uint16(bf.ReadUint32())
|
m.Quantity1 = uint16(bf.ReadUint32())
|
||||||
m.Quantity2 = uint16(bf.ReadUint32())
|
m.Quantity2 = uint16(bf.ReadUint32())
|
||||||
} else {
|
|
||||||
m.Reward1 = 10
|
|
||||||
m.Reward2 = 10
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
BEGIN;
|
|
||||||
|
|
||||||
ALTER TABLE distribution ADD COLUMN rights INTEGER;
|
|
||||||
ALTER TABLE distribution ADD COLUMN selection BOOLEAN;
|
|
||||||
|
|
||||||
END;
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
BEGIN;
|
|
||||||
|
|
||||||
ALTER TABLE IF EXISTS public.guild_applications DROP COLUMN IF EXISTS actor_id;
|
|
||||||
|
|
||||||
ALTER TABLE IF EXISTS public.guild_applications DROP COLUMN IF EXISTS application_type;
|
|
||||||
|
|
||||||
ALTER TABLE IF EXISTS public.guild_applications
|
|
||||||
ALTER COLUMN created_at DROP NOT NULL;
|
|
||||||
ALTER TABLE IF EXISTS public.guild_applications DROP CONSTRAINT IF EXISTS guild_applications_actor_id_fkey;
|
|
||||||
|
|
||||||
create table public.guild_invites (
|
|
||||||
id serial primary key,
|
|
||||||
guild_id integer,
|
|
||||||
character_id integer,
|
|
||||||
actor_id integer,
|
|
||||||
created_at timestamp with time zone not null default now(),
|
|
||||||
foreign key (guild_id) references guilds (id),
|
|
||||||
foreign key (character_id) references characters (id),
|
|
||||||
foreign key (actor_id) references characters (id)
|
|
||||||
);
|
|
||||||
|
|
||||||
drop type if exists guild_application_type;
|
|
||||||
|
|
||||||
ALTER TABLE IF EXISTS public.mail DROP CONSTRAINT IF EXISTS mail_sender_id_fkey;
|
|
||||||
|
|
||||||
END;
|
|
||||||
@@ -811,11 +811,6 @@ func handleMsgMhfEnumeratePrice(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfEnumerateOrder(s *Session, p mhfpacket.MHFPacket) {
|
|
||||||
pkt := p.(*mhfpacket.MsgMhfEnumerateOrder)
|
|
||||||
stubEnumerateNoResults(s, pkt.AckHandle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMsgMhfGetExtraInfo(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfGetExtraInfo(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
func userGetItems(s *Session) []mhfitem.MHFItemStack {
|
func userGetItems(s *Session) []mhfitem.MHFItemStack {
|
||||||
@@ -1051,58 +1046,32 @@ func handleMsgMhfUpdateEtcPoint(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfStampcardStamp(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfStampcardStamp(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfStampcardStamp)
|
pkt := p.(*mhfpacket.MsgMhfStampcardStamp)
|
||||||
|
|
||||||
rewards := []struct {
|
|
||||||
HR uint16
|
|
||||||
Item1 uint16
|
|
||||||
Quantity1 uint16
|
|
||||||
Item2 uint16
|
|
||||||
Quantity2 uint16
|
|
||||||
}{
|
|
||||||
{0, 6164, 1, 6164, 2},
|
|
||||||
{50, 6164, 2, 6164, 3},
|
|
||||||
{100, 6164, 3, 5392, 1},
|
|
||||||
{300, 5392, 1, 5392, 3},
|
|
||||||
{999, 5392, 1, 5392, 4},
|
|
||||||
}
|
|
||||||
if _config.ErupeConfig.RealClientMode <= _config.Z1 {
|
|
||||||
for _, reward := range rewards {
|
|
||||||
if pkt.HR >= reward.HR {
|
|
||||||
pkt.Item1 = reward.Item1
|
|
||||||
pkt.Quantity1 = reward.Quantity1
|
|
||||||
pkt.Item2 = reward.Item2
|
|
||||||
pkt.Quantity2 = reward.Quantity2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bf.WriteUint16(pkt.HR)
|
bf.WriteUint16(pkt.HR)
|
||||||
|
var stamps uint16
|
||||||
|
_ = s.server.db.QueryRow(`SELECT stampcard FROM characters WHERE id = $1`, s.charID).Scan(&stamps)
|
||||||
if _config.ErupeConfig.RealClientMode >= _config.G1 {
|
if _config.ErupeConfig.RealClientMode >= _config.G1 {
|
||||||
bf.WriteUint16(pkt.GR)
|
bf.WriteUint16(pkt.GR)
|
||||||
}
|
}
|
||||||
var stamps, rewardTier, rewardUnk uint16
|
|
||||||
reward := mhfitem.MHFItemStack{Item: mhfitem.MHFItem{}}
|
|
||||||
s.server.db.QueryRow(`UPDATE characters SET stampcard = stampcard + $1 WHERE id = $2 RETURNING stampcard`, pkt.Stamps, s.charID).Scan(&stamps)
|
|
||||||
bf.WriteUint16(stamps - pkt.Stamps)
|
|
||||||
bf.WriteUint16(stamps)
|
bf.WriteUint16(stamps)
|
||||||
|
stamps += pkt.Stamps
|
||||||
if stamps/30 > (stamps-pkt.Stamps)/30 {
|
bf.WriteUint16(stamps)
|
||||||
rewardTier = 2
|
s.server.db.Exec(`UPDATE characters SET stampcard = $1 WHERE id = $2`, stamps, s.charID)
|
||||||
rewardUnk = pkt.Reward2
|
if stamps%30 == 0 {
|
||||||
reward = mhfitem.MHFItemStack{Item: mhfitem.MHFItem{ItemID: pkt.Item2}, Quantity: pkt.Quantity2}
|
bf.WriteUint16(2)
|
||||||
addWarehouseItem(s, reward)
|
bf.WriteUint16(pkt.Reward2)
|
||||||
} else if stamps/15 > (stamps-pkt.Stamps)/15 {
|
bf.WriteUint16(pkt.Item2)
|
||||||
rewardTier = 1
|
bf.WriteUint16(pkt.Quantity2)
|
||||||
rewardUnk = pkt.Reward1
|
addWarehouseItem(s, mhfitem.MHFItemStack{Item: mhfitem.MHFItem{ItemID: pkt.Item2}, Quantity: pkt.Quantity2})
|
||||||
reward = mhfitem.MHFItemStack{Item: mhfitem.MHFItem{ItemID: pkt.Item1}, Quantity: pkt.Quantity1}
|
} else if stamps%15 == 0 {
|
||||||
addWarehouseItem(s, reward)
|
bf.WriteUint16(1)
|
||||||
|
bf.WriteUint16(pkt.Reward1)
|
||||||
|
bf.WriteUint16(pkt.Item1)
|
||||||
|
bf.WriteUint16(pkt.Quantity1)
|
||||||
|
addWarehouseItem(s, mhfitem.MHFItemStack{Item: mhfitem.MHFItem{ItemID: pkt.Item1}, Quantity: pkt.Quantity1})
|
||||||
|
} else {
|
||||||
|
bf.WriteBytes(make([]byte, 8))
|
||||||
}
|
}
|
||||||
|
|
||||||
bf.WriteUint16(rewardTier)
|
|
||||||
bf.WriteUint16(rewardUnk)
|
|
||||||
bf.WriteUint16(reward.Item.ItemID)
|
|
||||||
bf.WriteUint16(reward.Quantity)
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
type Distribution struct {
|
type Distribution struct {
|
||||||
ID uint32 `db:"id"`
|
ID uint32 `db:"id"`
|
||||||
Deadline time.Time `db:"deadline"`
|
Deadline time.Time `db:"deadline"`
|
||||||
Rights uint32 `db:"rights"`
|
|
||||||
TimesAcceptable uint16 `db:"times_acceptable"`
|
TimesAcceptable uint16 `db:"times_acceptable"`
|
||||||
TimesAccepted uint16 `db:"times_accepted"`
|
TimesAccepted uint16 `db:"times_accepted"`
|
||||||
MinHR int16 `db:"min_hr"`
|
MinHR int16 `db:"min_hr"`
|
||||||
@@ -24,7 +23,7 @@ type Distribution struct {
|
|||||||
MaxGR int16 `db:"max_gr"`
|
MaxGR int16 `db:"max_gr"`
|
||||||
EventName string `db:"event_name"`
|
EventName string `db:"event_name"`
|
||||||
Description string `db:"description"`
|
Description string `db:"description"`
|
||||||
Selection bool `db:"selection"`
|
Data []byte `db:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
|
||||||
@@ -33,7 +32,7 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
var itemDists []Distribution
|
var itemDists []Distribution
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
rows, err := s.server.db.Queryx(`
|
rows, err := s.server.db.Queryx(`
|
||||||
SELECT d.id, event_name, description, COALESCE(rights, 0) AS rights, COALESCE(selection, false) AS selection, times_acceptable,
|
SELECT d.id, event_name, description, times_acceptable,
|
||||||
COALESCE(min_hr, -1) AS min_hr, COALESCE(max_hr, -1) AS max_hr,
|
COALESCE(min_hr, -1) AS min_hr, COALESCE(max_hr, -1) AS max_hr,
|
||||||
COALESCE(min_sr, -1) AS min_sr, COALESCE(max_sr, -1) AS max_sr,
|
COALESCE(min_sr, -1) AS min_sr, COALESCE(max_sr, -1) AS max_sr,
|
||||||
COALESCE(min_gr, -1) AS min_gr, COALESCE(max_gr, -1) AS max_gr,
|
COALESCE(min_gr, -1) AS min_gr, COALESCE(max_gr, -1) AS max_gr,
|
||||||
@@ -61,7 +60,7 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
for _, dist := range itemDists {
|
for _, dist := range itemDists {
|
||||||
bf.WriteUint32(dist.ID)
|
bf.WriteUint32(dist.ID)
|
||||||
bf.WriteUint32(uint32(dist.Deadline.Unix()))
|
bf.WriteUint32(uint32(dist.Deadline.Unix()))
|
||||||
bf.WriteUint32(dist.Rights)
|
bf.WriteUint32(0) // Unk
|
||||||
bf.WriteUint16(dist.TimesAcceptable)
|
bf.WriteUint16(dist.TimesAcceptable)
|
||||||
bf.WriteUint16(dist.TimesAccepted)
|
bf.WriteUint16(dist.TimesAccepted)
|
||||||
if _config.ErupeConfig.RealClientMode >= _config.G9 {
|
if _config.ErupeConfig.RealClientMode >= _config.G9 {
|
||||||
@@ -80,11 +79,7 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint16(0) // Unk
|
bf.WriteUint16(0) // Unk
|
||||||
}
|
}
|
||||||
if _config.ErupeConfig.RealClientMode >= _config.G8 {
|
if _config.ErupeConfig.RealClientMode >= _config.G8 {
|
||||||
if dist.Selection {
|
bf.WriteUint8(0) // Unk
|
||||||
bf.WriteUint8(2) // Selection
|
|
||||||
} else {
|
|
||||||
bf.WriteUint8(0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if _config.ErupeConfig.RealClientMode >= _config.G7 {
|
if _config.ErupeConfig.RealClientMode >= _config.G7 {
|
||||||
bf.WriteUint16(0) // Unk
|
bf.WriteUint16(0) // Unk
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package channelserver
|
|||||||
import (
|
import (
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
ps "erupe-ce/common/pascalstring"
|
ps "erupe-ce/common/pascalstring"
|
||||||
|
"erupe-ce/common/stringsupport"
|
||||||
"erupe-ce/common/token"
|
"erupe-ce/common/token"
|
||||||
_config "erupe-ce/config"
|
_config "erupe-ce/config"
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
@@ -33,62 +34,180 @@ func handleMsgMhfLoadMezfesData(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateTournamentTimestamps(start uint32, debug bool) []uint32 {
|
||||||
|
timestamps := make([]uint32, 4)
|
||||||
|
midnight := TimeMidnight()
|
||||||
|
if debug && start <= 3 {
|
||||||
|
midnight := uint32(midnight.Unix())
|
||||||
|
switch start {
|
||||||
|
case 1:
|
||||||
|
timestamps[0] = midnight
|
||||||
|
timestamps[1] = timestamps[0] + 259200
|
||||||
|
timestamps[2] = timestamps[1] + 766800
|
||||||
|
timestamps[3] = timestamps[2] + 604800
|
||||||
|
case 2:
|
||||||
|
timestamps[0] = midnight - 259200
|
||||||
|
timestamps[1] = midnight
|
||||||
|
timestamps[2] = timestamps[1] + 766800
|
||||||
|
timestamps[3] = timestamps[2] + 604800
|
||||||
|
case 3:
|
||||||
|
timestamps[0] = midnight - 1026000
|
||||||
|
timestamps[1] = midnight - 766800
|
||||||
|
timestamps[2] = midnight
|
||||||
|
timestamps[3] = timestamps[2] + 604800
|
||||||
|
}
|
||||||
|
return timestamps
|
||||||
|
}
|
||||||
|
timestamps[0] = start
|
||||||
|
timestamps[1] = timestamps[0] + 259200
|
||||||
|
timestamps[2] = timestamps[1] + 766800
|
||||||
|
timestamps[3] = timestamps[2] + 604800
|
||||||
|
return timestamps
|
||||||
|
}
|
||||||
|
|
||||||
|
type TournamentEvent struct {
|
||||||
|
ID uint32
|
||||||
|
CupGroup uint16
|
||||||
|
EventSubType int16
|
||||||
|
QuestFileID uint32
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TournamentCup struct {
|
||||||
|
ID uint32
|
||||||
|
CupGroup uint16
|
||||||
|
Type uint16
|
||||||
|
Unk uint16
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfEnumerateRanking)
|
pkt := p.(*mhfpacket.MsgMhfEnumerateRanking)
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
state := s.server.erupeConfig.DebugOptions.TournamentOverride
|
|
||||||
// Unk
|
id, start := uint32(0xBEEFDEAD), uint32(0)
|
||||||
// Unk
|
rows, _ := s.server.db.Queryx("SELECT id, (EXTRACT(epoch FROM start_time)::int) as start_time FROM events WHERE event_type='festa'")
|
||||||
// Start?
|
for rows.Next() {
|
||||||
// End?
|
rows.Scan(&id, &start)
|
||||||
midnight := TimeMidnight()
|
}
|
||||||
switch state {
|
|
||||||
case 1:
|
var timestamps []uint32
|
||||||
bf.WriteUint32(uint32(midnight.Unix()))
|
if s.server.erupeConfig.DebugOptions.TournamentOverride >= 0 {
|
||||||
bf.WriteUint32(uint32(midnight.Add(3 * 24 * time.Hour).Unix()))
|
if s.server.erupeConfig.DebugOptions.TournamentOverride == 0 {
|
||||||
bf.WriteUint32(uint32(midnight.Add(13 * 24 * time.Hour).Unix()))
|
bf.WriteBytes(make([]byte, 16))
|
||||||
bf.WriteUint32(uint32(midnight.Add(20 * 24 * time.Hour).Unix()))
|
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||||
case 2:
|
bf.WriteUint8(0)
|
||||||
bf.WriteUint32(uint32(midnight.Add(-3 * 24 * time.Hour).Unix()))
|
ps.Uint8(bf, "", true)
|
||||||
bf.WriteUint32(uint32(midnight.Unix()))
|
bf.WriteUint16(0)
|
||||||
bf.WriteUint32(uint32(midnight.Add(10 * 24 * time.Hour).Unix()))
|
bf.WriteUint8(0)
|
||||||
bf.WriteUint32(uint32(midnight.Add(17 * 24 * time.Hour).Unix()))
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
case 3:
|
return
|
||||||
bf.WriteUint32(uint32(midnight.Add(-13 * 24 * time.Hour).Unix()))
|
}
|
||||||
bf.WriteUint32(uint32(midnight.Add(-10 * 24 * time.Hour).Unix()))
|
timestamps = generateTournamentTimestamps(uint32(s.server.erupeConfig.DebugOptions.TournamentOverride), true)
|
||||||
bf.WriteUint32(uint32(midnight.Unix()))
|
} else {
|
||||||
bf.WriteUint32(uint32(midnight.Add(7 * 24 * time.Hour).Unix()))
|
timestamps = generateTournamentTimestamps(start, false)
|
||||||
default:
|
}
|
||||||
|
|
||||||
|
if timestamps[0] > uint32(TimeAdjusted().Unix()) {
|
||||||
bf.WriteBytes(make([]byte, 16))
|
bf.WriteBytes(make([]byte, 16))
|
||||||
bf.WriteUint32(uint32(TimeAdjusted().Unix())) // TS Current Time
|
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||||
bf.WriteUint8(3)
|
bf.WriteUint8(0)
|
||||||
bf.WriteBytes(make([]byte, 4))
|
ps.Uint8(bf, "", true)
|
||||||
|
bf.WriteUint16(0)
|
||||||
|
bf.WriteUint8(0)
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bf.WriteUint32(uint32(TimeAdjusted().Unix())) // TS Current Time
|
|
||||||
bf.WriteUint8(3)
|
|
||||||
ps.Uint8(bf, "", false)
|
|
||||||
bf.WriteUint16(0) // numEvents
|
|
||||||
bf.WriteUint8(0) // numCups
|
|
||||||
|
|
||||||
/*
|
for _, timestamp := range timestamps {
|
||||||
struct event
|
bf.WriteUint32(timestamp)
|
||||||
uint32 eventID
|
}
|
||||||
uint16 unk
|
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||||
uint16 unk
|
bf.WriteUint8(1) // TODO: Make this dynamic depending on timestamp
|
||||||
uint32 unk
|
ps.Uint8(bf, "第150回公式狩猟大会", true)
|
||||||
psUint8 name
|
|
||||||
|
|
||||||
struct cup
|
// Temp direct port
|
||||||
uint32 cupID
|
tournamentEvents := []TournamentEvent{
|
||||||
uint16 unk
|
{2644, 16, 0, 60691, "爆霧竜討伐!"},
|
||||||
uint16 unk
|
{2645, 16, 1, 60691, "爆霧竜討伐!"},
|
||||||
uint16 unk
|
{2646, 16, 2, 60691, "爆霧竜討伐!"},
|
||||||
psUint8 name
|
{2647, 16, 3, 60691, "爆霧竜討伐!"},
|
||||||
psUint16 desc
|
{2648, 16, 4, 60691, "爆霧竜討伐!"},
|
||||||
*/
|
{2649, 16, 5, 60691, "爆霧竜討伐!"},
|
||||||
|
{2650, 16, 6, 60691, "爆霧竜討伐!"},
|
||||||
|
{2651, 16, 7, 60691, "爆霧竜討伐!"},
|
||||||
|
{2652, 16, 8, 60691, "爆霧竜討伐!"},
|
||||||
|
{2653, 16, 9, 60691, "爆霧竜討伐!"},
|
||||||
|
{2654, 16, 10, 60691, "爆霧竜討伐!"},
|
||||||
|
{2655, 16, 11, 60691, "爆霧竜討伐!"},
|
||||||
|
{2656, 16, 12, 60691, "爆霧竜討伐!"},
|
||||||
|
{2657, 16, 13, 60691, "爆霧竜討伐!"},
|
||||||
|
{2658, 17, -1, 60690, "みんなで爆霧竜討伐!"},
|
||||||
|
{2659, 6, 234, 0, "キレアジ"},
|
||||||
|
{2660, 6, 237, 0, "ハリマグロ"},
|
||||||
|
{2661, 6, 239, 0, "カクサンデメキン"},
|
||||||
|
}
|
||||||
|
tournamentCups := []TournamentCup{
|
||||||
|
{569, 6, 6, 0, "個人 巨大魚杯", "~C05【競技内容】\n~C00クエストで釣った魚のサイズを競う\n~C04【対象魚】\n~C00キレアジ、\nハリマグロ、カクサンデメキン\n~C07【入賞賞品】\n~C00魚杯のしるし、タルネコ生産券、\nグーク生産券、グーク足生産券、\nグーク解放券(1〜3位)\n/猟団ポイント(1〜100位)\n/匠チケット+ハーフチケット白\n(1〜500位)\n~C03【開催期間】\n~C002019年11月22日 14:00から\n2019年11月25日 14:00まで"},
|
||||||
|
{570, 17, 7, 0, "猟団 G級韋駄天杯", "~C05【競技内容】\n~C00≪みんなで爆霧竜討伐!≫を\n同じ猟団に所属する4人までの\n猟団員でいかに早くクリアするか\nを競う\n\n~C07【入賞賞品】\n~C00第147回狩人祭の魂(1〜200位)\n\n~C03【開催期間】\n~C002019年11月22日 14:00から\n2019年11月25日 14:00まで\n\n"},
|
||||||
|
{571, 16, 7, 0, "個人 G級韋駄天杯", "~C05【競技内容】\n~C00≪爆霧竜討伐!≫を\nいかに早くクリアするかを競う\n\n~C07【入賞賞品】\n~C00王者のメダル(1位)\n/公式のしるし、タルネコ生産券、\nグーク生産券、グーク足生産券、\nグーク解放券(1〜3位)\n/猟団ポイント(1〜100位)\n/匠チケット+ハーフチケット白\n(1〜500位)\n~C03【開催期間】\n~C002019年11月22日 14:00から\n2019年11月25日 14:00まで"},
|
||||||
|
}
|
||||||
|
|
||||||
|
bf.WriteUint16(uint16(len(tournamentEvents)))
|
||||||
|
for _, event := range tournamentEvents {
|
||||||
|
bf.WriteUint32(event.ID)
|
||||||
|
bf.WriteUint16(event.CupGroup)
|
||||||
|
bf.WriteInt16(event.EventSubType)
|
||||||
|
bf.WriteUint32(event.QuestFileID)
|
||||||
|
ps.Uint8(bf, event.Name, true)
|
||||||
|
}
|
||||||
|
bf.WriteUint8(uint8(len(tournamentCups)))
|
||||||
|
for _, cup := range tournamentCups {
|
||||||
|
bf.WriteUint32(cup.ID)
|
||||||
|
bf.WriteUint16(cup.CupGroup)
|
||||||
|
bf.WriteUint16(cup.Type)
|
||||||
|
bf.WriteUint16(cup.Unk)
|
||||||
|
ps.Uint8(bf, cup.Name, true)
|
||||||
|
ps.Uint16(bf, cup.Description, true)
|
||||||
|
}
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
|
}
|
||||||
|
|
||||||
|
type TournamentRank struct {
|
||||||
|
CID uint32
|
||||||
|
Rank uint32
|
||||||
|
Grade uint16
|
||||||
|
HR uint16
|
||||||
|
GR uint16
|
||||||
|
CharName string
|
||||||
|
GuildName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMsgMhfEnumerateOrder(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfEnumerateOrder)
|
||||||
|
bf := byteframe.NewByteFrame()
|
||||||
|
bf.WriteUint32(pkt.EventID)
|
||||||
|
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||||
|
|
||||||
|
tournamentRanks := []TournamentRank{}
|
||||||
|
bf.WriteUint16(uint16(len(tournamentRanks)))
|
||||||
|
bf.WriteUint16(0) // Unk
|
||||||
|
for _, rank := range tournamentRanks {
|
||||||
|
bf.WriteUint32(rank.CID)
|
||||||
|
bf.WriteUint32(rank.Rank)
|
||||||
|
bf.WriteUint16(rank.Grade)
|
||||||
|
bf.WriteUint16(0)
|
||||||
|
bf.WriteUint16(rank.HR)
|
||||||
|
if _config.ErupeConfig.RealClientMode >= _config.G10 {
|
||||||
|
bf.WriteUint16(rank.GR)
|
||||||
|
}
|
||||||
|
bf.WriteUint16(0)
|
||||||
|
bf.WriteUint8(uint8(len(rank.CharName) + 1))
|
||||||
|
bf.WriteUint8(uint8(len(rank.GuildName) + 1))
|
||||||
|
bf.WriteNullTerminatedBytes(stringsupport.UTF8ToSJIS(rank.CharName))
|
||||||
|
bf.WriteNullTerminatedBytes(stringsupport.UTF8ToSJIS(rank.GuildName))
|
||||||
|
}
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,10 +246,10 @@ func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 {
|
|||||||
}
|
}
|
||||||
return timestamps
|
return timestamps
|
||||||
}
|
}
|
||||||
if start == 0 || TimeAdjusted().Unix() > int64(start)+2977200 {
|
if start == 0 || TimeAdjusted().Unix() > int64(start)+3024000 {
|
||||||
cleanupFesta(s)
|
cleanupFesta(s)
|
||||||
// Generate a new festa, starting midnight tomorrow
|
// Generate a new festa, starting 11am tomorrow
|
||||||
start = uint32(midnight.Add(24 * time.Hour).Unix())
|
start = uint32(midnight.Add(35 * time.Hour).Unix())
|
||||||
s.server.db.Exec("INSERT INTO events (event_type, start_time) VALUES ('festa', to_timestamp($1)::timestamp without time zone)", start)
|
s.server.db.Exec("INSERT INTO events (event_type, start_time) VALUES ('festa', to_timestamp($1)::timestamp without time zone)", start)
|
||||||
}
|
}
|
||||||
timestamps[0] = start
|
timestamps[0] = start
|
||||||
@@ -356,14 +475,18 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
// state festa (U)ser
|
// state festa (U)ser
|
||||||
func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfStateFestaU)
|
pkt := p.(*mhfpacket.MsgMhfStateFestaU)
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if guild.ID == 0 || IsGuildApplicant(s, s.charID) {
|
applicant := false
|
||||||
|
if guild != nil {
|
||||||
|
applicant, _ = guild.HasApplicationForCharID(s, s.charID)
|
||||||
|
}
|
||||||
|
if err != nil || guild == nil || applicant {
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var souls, exists uint32
|
var souls, exists uint32
|
||||||
s.server.db.QueryRow(`SELECT COALESCE((SELECT SUM(souls) FROM festa_submissions WHERE character_id=$1), 0)`, s.charID).Scan(&souls)
|
s.server.db.QueryRow(`SELECT COALESCE((SELECT SUM(souls) FROM festa_submissions WHERE character_id=$1), 0)`, s.charID).Scan(&souls)
|
||||||
err := s.server.db.QueryRow("SELECT prize_id FROM festa_prizes_accepted WHERE prize_id=0 AND character_id=$1", s.charID).Scan(&exists)
|
err = s.server.db.QueryRow("SELECT prize_id FROM festa_prizes_accepted WHERE prize_id=0 AND character_id=$1", s.charID).Scan(&exists)
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bf.WriteUint32(souls)
|
bf.WriteUint32(souls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -379,9 +502,13 @@ func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
// state festa (G)uild
|
// state festa (G)uild
|
||||||
func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfStateFestaG)
|
pkt := p.(*mhfpacket.MsgMhfStateFestaG)
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
|
applicant := false
|
||||||
|
if guild != nil {
|
||||||
|
applicant, _ = guild.HasApplicationForCharID(s, s.charID)
|
||||||
|
}
|
||||||
resp := byteframe.NewByteFrame()
|
resp := byteframe.NewByteFrame()
|
||||||
if guild.ID == 0 || IsGuildApplicant(s, s.charID) {
|
if err != nil || guild == nil || applicant {
|
||||||
resp.WriteUint32(0)
|
resp.WriteUint32(0)
|
||||||
resp.WriteInt32(0)
|
resp.WriteInt32(0)
|
||||||
resp.WriteInt32(-1)
|
resp.WriteInt32(-1)
|
||||||
@@ -400,20 +527,20 @@ func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfEnumerateFestaMember)
|
pkt := p.(*mhfpacket.MsgMhfEnumerateFestaMember)
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if guild.ID == 0 {
|
if err != nil || guild == nil {
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
members := GetGuildMembers(s, guild.ID)
|
members, err := GetGuildMembers(s, guild.ID, false)
|
||||||
if len(members) == 0 {
|
if err != nil {
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sort.Slice(members, func(i, j int) bool {
|
sort.Slice(members, func(i, j int) bool {
|
||||||
return members[i].Souls > members[j].Souls
|
return members[i].Souls > members[j].Souls
|
||||||
})
|
})
|
||||||
var validMembers []GuildMember
|
var validMembers []*GuildMember
|
||||||
for _, member := range members {
|
for _, member := range members {
|
||||||
if member.Souls > 0 {
|
if member.Souls > 0 {
|
||||||
validMembers = append(validMembers, member)
|
validMembers = append(validMembers, member)
|
||||||
@@ -442,8 +569,8 @@ func handleMsgMhfVoteFesta(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfEntryFesta(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEntryFesta(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfEntryFesta)
|
pkt := p.(*mhfpacket.MsgMhfEntryFesta)
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if guild.ID == 0 {
|
if err != nil || guild == nil {
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,9 +66,13 @@ type Guild struct {
|
|||||||
Souls uint32 `db:"souls"`
|
Souls uint32 `db:"souls"`
|
||||||
AllianceID uint32 `db:"alliance_id"`
|
AllianceID uint32 `db:"alliance_id"`
|
||||||
Icon *GuildIcon `db:"icon"`
|
Icon *GuildIcon `db:"icon"`
|
||||||
LeaderCharID uint32 `db:"leader_id"`
|
|
||||||
LeaderName string `db:"leader_name"`
|
GuildLeader
|
||||||
Members []*GuildMember
|
}
|
||||||
|
|
||||||
|
type GuildLeader struct {
|
||||||
|
LeaderCharID uint32 `db:"leader_id"`
|
||||||
|
LeaderName string `db:"leader_name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GuildIconPart struct {
|
type GuildIconPart struct {
|
||||||
@@ -85,23 +89,12 @@ type GuildIconPart struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GuildApplication struct {
|
type GuildApplication struct {
|
||||||
GuildID uint32 `db:"guild_id"`
|
ID int `db:"id"`
|
||||||
CharID uint32 `db:"character_id"`
|
GuildID uint32 `db:"guild_id"`
|
||||||
AppliedAt time.Time `db:"created_at"`
|
CharID uint32 `db:"character_id"`
|
||||||
HR uint16 `db:"hr"`
|
ActorID uint32 `db:"actor_id"`
|
||||||
GR uint16 `db:"gr"`
|
ApplicationType GuildApplicationType `db:"application_type"`
|
||||||
Name string `db:"name"`
|
CreatedAt time.Time `db:"created_at"`
|
||||||
}
|
|
||||||
|
|
||||||
type GuildInvite struct {
|
|
||||||
ID uint32 `db:"id"`
|
|
||||||
GuildID uint32 `db:"guild_id"`
|
|
||||||
CharID uint32 `db:"character_id"`
|
|
||||||
ActorID uint32 `db:"actor_id"`
|
|
||||||
InvitedAt time.Time `db:"created_at"`
|
|
||||||
HR uint16 `db:"hr"`
|
|
||||||
GR uint16 `db:"gr"`
|
|
||||||
Name string `db:"name"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type GuildIcon struct {
|
type GuildIcon struct {
|
||||||
@@ -198,7 +191,7 @@ func (guild *Guild) Save(s *Session) error {
|
|||||||
UPDATE guilds SET main_motto=$2, sub_motto=$3, comment=$4, pugi_name_1=$5, pugi_name_2=$6, pugi_name_3=$7,
|
UPDATE guilds SET main_motto=$2, sub_motto=$3, comment=$4, pugi_name_1=$5, pugi_name_2=$6, pugi_name_3=$7,
|
||||||
pugi_outfit_1=$8, pugi_outfit_2=$9, pugi_outfit_3=$10, pugi_outfits=$11, icon=$12, leader_id=$13 WHERE id=$1
|
pugi_outfit_1=$8, pugi_outfit_2=$9, pugi_outfit_3=$10, pugi_outfits=$11, icon=$12, leader_id=$13 WHERE id=$1
|
||||||
`, guild.ID, guild.MainMotto, guild.SubMotto, guild.Comment, guild.PugiName1, guild.PugiName2, guild.PugiName3,
|
`, guild.ID, guild.MainMotto, guild.SubMotto, guild.Comment, guild.PugiName1, guild.PugiName2, guild.PugiName3,
|
||||||
guild.PugiOutfit1, guild.PugiOutfit2, guild.PugiOutfit3, guild.PugiOutfits, guild.Icon, guild.LeaderCharID)
|
guild.PugiOutfit1, guild.PugiOutfit2, guild.PugiOutfit3, guild.PugiOutfits, guild.Icon, guild.GuildLeader.LeaderCharID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("failed to update guild data", zap.Error(err), zap.Uint32("guildID", guild.ID))
|
s.logger.Error("failed to update guild data", zap.Error(err), zap.Uint32("guildID", guild.ID))
|
||||||
@@ -356,8 +349,13 @@ func (guild *Guild) AcceptApplication(s *Session, charID uint32) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is relying on the fact that invitation ID is also character ID right now
|
||||||
|
// if invitation ID changes, this will break.
|
||||||
func (guild *Guild) CancelInvitation(s *Session, charID uint32) error {
|
func (guild *Guild) CancelInvitation(s *Session, charID uint32) error {
|
||||||
_, err := s.server.db.Exec(`DELETE FROM guild_invites WHERE character_id = $1 AND guild_id = $2`, charID, guild.ID)
|
_, err := s.server.db.Exec(
|
||||||
|
`DELETE FROM guild_applications WHERE character_id = $1 AND guild_id = $2 AND application_type = 'invited'`,
|
||||||
|
charID, guild.ID,
|
||||||
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error(
|
s.logger.Error(
|
||||||
@@ -449,17 +447,6 @@ func (guild *Guild) GetApplicationForCharID(s *Session, charID uint32, applicati
|
|||||||
return application, nil
|
return application, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsGuildApplicant(s *Session, charID uint32) bool {
|
|
||||||
var exists bool
|
|
||||||
err := s.server.db.QueryRowx(`
|
|
||||||
SELECT 1 from guild_applications WHERE character_id = $1
|
|
||||||
`, charID).Scan(&exists)
|
|
||||||
if err == nil && exists {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (guild *Guild) HasApplicationForCharID(s *Session, charID uint32) (bool, error) {
|
func (guild *Guild) HasApplicationForCharID(s *Session, charID uint32) (bool, error) {
|
||||||
row := s.server.db.QueryRowx(`
|
row := s.server.db.QueryRowx(`
|
||||||
SELECT 1 from guild_applications WHERE character_id = $1 AND guild_id = $2
|
SELECT 1 from guild_applications WHERE character_id = $1 AND guild_id = $2
|
||||||
@@ -558,43 +545,62 @@ func rollbackTransaction(s *Session, transaction *sql.Tx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGuildInfoByID(s *Session, guildID uint32) Guild {
|
func GetGuildInfoByID(s *Session, guildID uint32) (*Guild, error) {
|
||||||
var guild Guild
|
rows, err := s.server.db.Queryx(fmt.Sprintf(`
|
||||||
err := s.server.db.QueryRowx(fmt.Sprintf(`
|
|
||||||
%s
|
%s
|
||||||
WHERE g.id = $1
|
WHERE g.id = $1
|
||||||
`, guildInfoSelectQuery), guildID).StructScan(&guild)
|
LIMIT 1
|
||||||
|
`, guildInfoSelectQuery), guildID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("failed to retrieve guild", zap.Error(err), zap.Uint32("guildID", guildID))
|
s.logger.Error("failed to retrieve guild", zap.Error(err), zap.Uint32("guildID", guildID))
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return guild
|
defer rows.Close()
|
||||||
|
|
||||||
|
hasRow := rows.Next()
|
||||||
|
|
||||||
|
if !hasRow {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildGuildObjectFromDbResult(rows, err, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGuildInfoByCharacterId(s *Session, charID uint32) Guild {
|
func GetGuildInfoByCharacterId(s *Session, charID uint32) (*Guild, error) {
|
||||||
var guild Guild
|
rows, err := s.server.db.Queryx(fmt.Sprintf(`
|
||||||
err := s.server.db.QueryRowx(fmt.Sprintf(`
|
|
||||||
%s
|
%s
|
||||||
WHERE EXISTS (
|
WHERE EXISTS(
|
||||||
SELECT 1
|
SELECT 1
|
||||||
FROM guild_characters gc1
|
FROM guild_characters gc1
|
||||||
WHERE gc1.character_id = $1
|
WHERE gc1.character_id = $1
|
||||||
AND gc1.guild_id = g.id
|
AND gc1.guild_id = g.id
|
||||||
) OR EXISTS (
|
)
|
||||||
SELECT 1
|
OR EXISTS(
|
||||||
FROM guild_applications ga
|
SELECT 1
|
||||||
WHERE ga.character_id = $1
|
FROM guild_applications ga
|
||||||
AND ga.guild_id = g.id
|
WHERE ga.character_id = $1
|
||||||
)
|
AND ga.guild_id = g.id
|
||||||
|
AND ga.application_type = 'applied'
|
||||||
|
)
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`, guildInfoSelectQuery), charID).StructScan(&guild)
|
`, guildInfoSelectQuery), charID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("failed to retrieve guild for character", zap.Error(err), zap.Uint32("charID", charID))
|
s.logger.Error("failed to retrieve guild for character", zap.Error(err), zap.Uint32("charID", charID))
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return guild
|
defer rows.Close()
|
||||||
|
|
||||||
|
hasRow := rows.Next()
|
||||||
|
|
||||||
|
if !hasRow {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildGuildObjectFromDbResult(rows, err, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildGuildObjectFromDbResult(result *sqlx.Rows, err error, s *Session) (*Guild, error) {
|
func buildGuildObjectFromDbResult(result *sqlx.Rows, err error, s *Session) (*Guild, error) {
|
||||||
@@ -636,10 +642,12 @@ func handleMsgMhfCreateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfOperateGuild)
|
pkt := p.(*mhfpacket.MsgMhfOperateGuild)
|
||||||
|
|
||||||
var err error
|
guild, err := GetGuildInfoByID(s, pkt.GuildID)
|
||||||
|
characterGuildInfo, err := GetCharacterGuildData(s, s.charID)
|
||||||
guild := GetGuildInfoByID(s, pkt.GuildID)
|
if err != nil {
|
||||||
characterGuildInfo := GetCharacterGuildData(s, s.charID)
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
|
|
||||||
@@ -657,8 +665,8 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
bf.WriteUint32(uint32(response))
|
bf.WriteUint32(uint32(response))
|
||||||
case mhfpacket.OperateGuildResign:
|
case mhfpacket.OperateGuildResign:
|
||||||
guildMembers := GetGuildMembers(s, guild.ID)
|
guildMembers, err := GetGuildMembers(s, guild.ID, false)
|
||||||
if len(guildMembers) > 0 {
|
if err == nil {
|
||||||
sort.Slice(guildMembers[:], func(i, j int) bool {
|
sort.Slice(guildMembers[:], func(i, j int) bool {
|
||||||
return guildMembers[i].OrderIndex < guildMembers[j].OrderIndex
|
return guildMembers[i].OrderIndex < guildMembers[j].OrderIndex
|
||||||
})
|
})
|
||||||
@@ -674,61 +682,71 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
guild.Save(s)
|
guild.Save(s)
|
||||||
} else {
|
|
||||||
bf.WriteUint32(0)
|
|
||||||
}
|
}
|
||||||
case mhfpacket.OperateGuildApply:
|
case mhfpacket.OperateGuildApply:
|
||||||
_, err = s.server.db.Exec(`INSERT INTO guild_applications (guild_id, character_id) VALUES ($1, $2)`, guild.ID, s.charID)
|
err = guild.CreateApplication(s, s.charID, GuildApplicationTypeApplied, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
bf.WriteUint32(guild.LeaderCharID)
|
bf.WriteUint32(guild.LeaderCharID)
|
||||||
} else {
|
} else {
|
||||||
bf.WriteUint32(0)
|
bf.WriteUint32(0)
|
||||||
}
|
}
|
||||||
case mhfpacket.OperateGuildLeave:
|
case mhfpacket.OperateGuildLeave:
|
||||||
if characterGuildInfo.CharID == 0 {
|
if characterGuildInfo.IsApplicant {
|
||||||
s.server.db.Exec(`DELETE FROM guild_applications WHERE character_id=$1 AND guild_id=$2`, s.charID, guild.ID)
|
err = guild.RejectApplication(s, s.charID)
|
||||||
bf.WriteUint32(1)
|
|
||||||
} else {
|
} else {
|
||||||
if guild.RemoveCharacter(s, s.charID) != nil {
|
err = guild.RemoveCharacter(s, s.charID)
|
||||||
bf.WriteUint32(0)
|
}
|
||||||
} else {
|
response := 1
|
||||||
bf.WriteUint32(1)
|
if err != nil {
|
||||||
|
response = 0
|
||||||
|
} else {
|
||||||
|
mail := Mail{
|
||||||
|
RecipientID: s.charID,
|
||||||
|
Subject: "Withdrawal",
|
||||||
|
Body: fmt.Sprintf("You have withdrawn from 「%s」.", guild.Name),
|
||||||
|
IsSystemMessage: true,
|
||||||
}
|
}
|
||||||
|
mail.Send(s, nil)
|
||||||
}
|
}
|
||||||
mail := Mail{
|
bf.WriteUint32(uint32(response))
|
||||||
RecipientID: s.charID,
|
|
||||||
Subject: "Withdrawal",
|
|
||||||
Body: fmt.Sprintf("You have withdrawn from 「%s」.", guild.Name),
|
|
||||||
IsSystemMessage: true,
|
|
||||||
}
|
|
||||||
mail.Send(s)
|
|
||||||
case mhfpacket.OperateGuildDonateRank:
|
case mhfpacket.OperateGuildDonateRank:
|
||||||
bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, 0))
|
bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, 0))
|
||||||
case mhfpacket.OperateGuildSetApplicationDeny:
|
case mhfpacket.OperateGuildSetApplicationDeny:
|
||||||
s.server.db.Exec(`UPDATE guilds SET recruiting=false WHERE id=$1`, guild.ID)
|
s.server.db.Exec("UPDATE guilds SET recruiting=false WHERE id=$1", guild.ID)
|
||||||
case mhfpacket.OperateGuildSetApplicationAllow:
|
case mhfpacket.OperateGuildSetApplicationAllow:
|
||||||
s.server.db.Exec(`UPDATE guilds SET recruiting=true WHERE id=$1`, guild.ID)
|
s.server.db.Exec("UPDATE guilds SET recruiting=true WHERE id=$1", guild.ID)
|
||||||
case mhfpacket.OperateGuildSetAvoidLeadershipTrue:
|
case mhfpacket.OperateGuildSetAvoidLeadershipTrue:
|
||||||
s.server.db.Exec(`UPDATE guild_characters SET avoid_leadership=true WHERE character_id=$1`, s.charID)
|
handleAvoidLeadershipUpdate(s, pkt, true)
|
||||||
case mhfpacket.OperateGuildSetAvoidLeadershipFalse:
|
case mhfpacket.OperateGuildSetAvoidLeadershipFalse:
|
||||||
s.server.db.Exec(`UPDATE guild_characters SET avoid_leadership=false WHERE character_id=$1`, s.charID)
|
handleAvoidLeadershipUpdate(s, pkt, false)
|
||||||
case mhfpacket.OperateGuildUpdateComment:
|
case mhfpacket.OperateGuildUpdateComment:
|
||||||
s.server.db.Exec(`UPDATE guilds SET comment=$1 WHERE id=$2`, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes()), guild.ID)
|
if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() {
|
||||||
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guild.Comment = stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())
|
||||||
|
guild.Save(s)
|
||||||
case mhfpacket.OperateGuildUpdateMotto:
|
case mhfpacket.OperateGuildUpdateMotto:
|
||||||
|
if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() {
|
||||||
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
_ = pkt.Data1.ReadUint16()
|
_ = pkt.Data1.ReadUint16()
|
||||||
s.server.db.Exec(`UPDATE guilds SET sub_motto=$1, main_motto=$2 WHERE id=$3`, pkt.Data1.ReadUint8(), pkt.Data1.ReadUint8(), guild.ID)
|
guild.SubMotto = pkt.Data1.ReadUint8()
|
||||||
|
guild.MainMotto = pkt.Data1.ReadUint8()
|
||||||
|
guild.Save(s)
|
||||||
case mhfpacket.OperateGuildRenamePugi1:
|
case mhfpacket.OperateGuildRenamePugi1:
|
||||||
guild.RenamePoogie(s, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes()), 1)
|
handleRenamePugi(s, pkt.Data2, guild, 1)
|
||||||
case mhfpacket.OperateGuildRenamePugi2:
|
case mhfpacket.OperateGuildRenamePugi2:
|
||||||
guild.RenamePoogie(s, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes()), 2)
|
handleRenamePugi(s, pkt.Data2, guild, 2)
|
||||||
case mhfpacket.OperateGuildRenamePugi3:
|
case mhfpacket.OperateGuildRenamePugi3:
|
||||||
guild.RenamePoogie(s, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes()), 3)
|
handleRenamePugi(s, pkt.Data2, guild, 3)
|
||||||
case mhfpacket.OperateGuildChangePugi1:
|
case mhfpacket.OperateGuildChangePugi1:
|
||||||
guild.ChangePoogie(s, uint8(pkt.Data1.ReadUint32()), 1)
|
handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 1)
|
||||||
case mhfpacket.OperateGuildChangePugi2:
|
case mhfpacket.OperateGuildChangePugi2:
|
||||||
guild.ChangePoogie(s, uint8(pkt.Data1.ReadUint32()), 2)
|
handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 2)
|
||||||
case mhfpacket.OperateGuildChangePugi3:
|
case mhfpacket.OperateGuildChangePugi3:
|
||||||
guild.ChangePoogie(s, uint8(pkt.Data1.ReadUint32()), 3)
|
handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 3)
|
||||||
case mhfpacket.OperateGuildUnlockOutfit:
|
case mhfpacket.OperateGuildUnlockOutfit:
|
||||||
// TODO: This doesn't implement blocking, if someone unlocked the same outfit at the same time
|
// TODO: This doesn't implement blocking, if someone unlocked the same outfit at the same time
|
||||||
s.server.db.Exec(`UPDATE guilds SET pugi_outfits=pugi_outfits+$1 WHERE id=$2`, int(math.Pow(float64(pkt.Data1.ReadUint32()), 2)), guild.ID)
|
s.server.db.Exec(`UPDATE guilds SET pugi_outfits=pugi_outfits+$1 WHERE id=$2`, int(math.Pow(float64(pkt.Data1.ReadUint32()), 2)), guild.ID)
|
||||||
@@ -756,31 +774,32 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Guild) RenamePoogie(s *Session, name string, num int) {
|
func handleRenamePugi(s *Session, bf *byteframe.ByteFrame, guild *Guild, num int) {
|
||||||
|
name := stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
|
||||||
switch num {
|
switch num {
|
||||||
case 1:
|
case 1:
|
||||||
g.PugiName1 = name
|
guild.PugiName1 = name
|
||||||
case 2:
|
case 2:
|
||||||
g.PugiName2 = name
|
guild.PugiName2 = name
|
||||||
default:
|
default:
|
||||||
g.PugiName3 = name
|
guild.PugiName3 = name
|
||||||
}
|
}
|
||||||
g.Save(s)
|
guild.Save(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Guild) ChangePoogie(s *Session, outfit uint8, num int) {
|
func handleChangePugi(s *Session, outfit uint8, guild *Guild, num int) {
|
||||||
switch num {
|
switch num {
|
||||||
case 1:
|
case 1:
|
||||||
g.PugiOutfit1 = outfit
|
guild.PugiOutfit1 = outfit
|
||||||
case 2:
|
case 2:
|
||||||
g.PugiOutfit2 = outfit
|
guild.PugiOutfit2 = outfit
|
||||||
case 3:
|
case 3:
|
||||||
g.PugiOutfit3 = outfit
|
guild.PugiOutfit3 = outfit
|
||||||
}
|
}
|
||||||
g.Save(s)
|
guild.Save(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleDonateRP(s *Session, amount uint16, guild Guild, _type int) []byte {
|
func handleDonateRP(s *Session, amount uint16, guild *Guild, _type int) []byte {
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bf.WriteUint32(0)
|
bf.WriteUint32(0)
|
||||||
saveData, err := GetCharacterSaveData(s, s.charID)
|
saveData, err := GetCharacterSaveData(s, s.charID)
|
||||||
@@ -816,42 +835,63 @@ func handleDonateRP(s *Session, amount uint16, guild Guild, _type int) []byte {
|
|||||||
return bf.Data()
|
return bf.Data()
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfOperateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
func handleAvoidLeadershipUpdate(s *Session, pkt *mhfpacket.MsgMhfOperateGuild, avoidLeadership bool) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfOperateGuildMember)
|
characterGuildData, err := GetCharacterGuildData(s, s.charID)
|
||||||
|
|
||||||
guild := GetGuildInfoByCharacterId(s, pkt.CharID)
|
if err != nil {
|
||||||
if guild.ID == 0 {
|
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
actor := GetCharacterGuildData(s, s.charID)
|
characterGuildData.AvoidLeadership = avoidLeadership
|
||||||
if !actor.IsSubLeader() {
|
|
||||||
|
err = characterGuildData.Save(s)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMsgMhfOperateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfOperateGuildMember)
|
||||||
|
|
||||||
|
guild, err := GetGuildInfoByCharacterId(s, pkt.CharID)
|
||||||
|
|
||||||
|
if err != nil || guild == nil {
|
||||||
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
actorCharacter, err := GetCharacterGuildData(s, s.charID)
|
||||||
|
|
||||||
|
if err != nil || (!actorCharacter.IsSubLeader() && guild.LeaderCharID != s.charID) {
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var mail Mail
|
var mail Mail
|
||||||
switch pkt.Action {
|
switch pkt.Action {
|
||||||
case mhfpacket.OperateGuildMemberAccept:
|
case mhfpacket.OPERATE_GUILD_MEMBER_ACTION_ACCEPT:
|
||||||
s.server.db.Exec(`DELETE FROM guild_applications WHERE character_id=$1`, pkt.CharID)
|
err = guild.AcceptApplication(s, pkt.CharID)
|
||||||
s.server.db.Exec(`INSERT INTO guild_characters (guild_id, character_id, order_index) VALUES ($1, $2, (SELECT MAX(order_index) + 1 FROM guild_characters WHERE guild_id = $1))`, guild.ID, pkt.CharID)
|
|
||||||
mail = Mail{
|
mail = Mail{
|
||||||
RecipientID: pkt.CharID,
|
RecipientID: pkt.CharID,
|
||||||
Subject: "Accepted!",
|
Subject: "Accepted!",
|
||||||
Body: fmt.Sprintf("Your application to join 「%s」 was accepted.", guild.Name),
|
Body: fmt.Sprintf("Your application to join 「%s」 was accepted.", guild.Name),
|
||||||
IsSystemMessage: true,
|
IsSystemMessage: true,
|
||||||
}
|
}
|
||||||
case mhfpacket.OperateGuildMemberReject:
|
case mhfpacket.OPERATE_GUILD_MEMBER_ACTION_REJECT:
|
||||||
s.server.db.Exec(`DELETE FROM guild_applications WHERE character_id=$1 AND guild_id=$2`, pkt.CharID, guild.ID)
|
err = guild.RejectApplication(s, pkt.CharID)
|
||||||
mail = Mail{
|
mail = Mail{
|
||||||
RecipientID: pkt.CharID,
|
RecipientID: pkt.CharID,
|
||||||
Subject: "Rejected",
|
Subject: "Rejected",
|
||||||
Body: fmt.Sprintf("Your application to join 「%s」 was rejected.", guild.Name),
|
Body: fmt.Sprintf("Your application to join 「%s」 was rejected.", guild.Name),
|
||||||
IsSystemMessage: true,
|
IsSystemMessage: true,
|
||||||
}
|
}
|
||||||
case mhfpacket.OperateGuildMemberKick:
|
case mhfpacket.OPERATE_GUILD_MEMBER_ACTION_KICK:
|
||||||
_ = guild.RemoveCharacter(s, pkt.CharID)
|
err = guild.RemoveCharacter(s, pkt.CharID)
|
||||||
mail = Mail{
|
mail = Mail{
|
||||||
RecipientID: pkt.CharID,
|
RecipientID: pkt.CharID,
|
||||||
Subject: "Kicked",
|
Subject: "Kicked",
|
||||||
@@ -863,8 +903,10 @@ func handleMsgMhfOperateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
s.logger.Warn(fmt.Sprintf("unhandled operateGuildMember action '%d'", pkt.Action))
|
s.logger.Warn(fmt.Sprintf("unhandled operateGuildMember action '%d'", pkt.Action))
|
||||||
}
|
}
|
||||||
|
|
||||||
if mail.RecipientID != 0 {
|
if err != nil {
|
||||||
mail.Send(s)
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
} else {
|
||||||
|
mail.Send(s, nil)
|
||||||
for _, channel := range s.server.Channels {
|
for _, channel := range s.server.Channels {
|
||||||
for _, session := range channel.sessions {
|
for _, session := range channel.sessions {
|
||||||
if session.charID == pkt.CharID {
|
if session.charID == pkt.CharID {
|
||||||
@@ -872,28 +914,44 @@ func handleMsgMhfOperateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
}
|
}
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfInfoGuild)
|
pkt := p.(*mhfpacket.MsgMhfInfoGuild)
|
||||||
|
|
||||||
var guild Guild
|
var guild *Guild
|
||||||
|
var err error
|
||||||
|
|
||||||
if pkt.GuildID > 0 {
|
if pkt.GuildID > 0 {
|
||||||
guild = GetGuildInfoByID(s, pkt.GuildID)
|
guild, err = GetGuildInfoByID(s, pkt.GuildID)
|
||||||
} else {
|
} else {
|
||||||
guild = GetGuildInfoByCharacterId(s, s.charID)
|
guild, err = GetGuildInfoByCharacterId(s, s.charID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if guild.ID > 0 {
|
if err == nil && guild != nil {
|
||||||
s.prevGuildID = guild.ID
|
s.prevGuildID = guild.ID
|
||||||
|
|
||||||
guildName := stringsupport.UTF8ToSJIS(guild.Name)
|
guildName := stringsupport.UTF8ToSJIS(guild.Name)
|
||||||
guildComment := stringsupport.UTF8ToSJIS(guild.Comment)
|
guildComment := stringsupport.UTF8ToSJIS(guild.Comment)
|
||||||
guildLeaderName := stringsupport.UTF8ToSJIS(guild.LeaderName)
|
guildLeaderName := stringsupport.UTF8ToSJIS(guild.LeaderName)
|
||||||
|
|
||||||
characterGuildData := GetCharacterGuildData(s, s.charID)
|
characterGuildData, err := GetCharacterGuildData(s, s.charID)
|
||||||
|
characterJoinedAt := uint32(0xFFFFFFFF)
|
||||||
|
|
||||||
|
if characterGuildData != nil && characterGuildData.JoinedAt != nil {
|
||||||
|
characterJoinedAt = uint32(characterGuildData.JoinedAt.Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
resp := byteframe.NewByteFrame()
|
||||||
|
resp.WriteUint32(0) // Count
|
||||||
|
resp.WriteUint8(0) // Unk, read if count == 0.
|
||||||
|
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
|
|
||||||
@@ -915,20 +973,16 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
bf.WriteBool(!guild.Recruiting)
|
bf.WriteBool(!guild.Recruiting)
|
||||||
|
|
||||||
if characterGuildData.CharID == 0 {
|
if characterGuildData == nil || characterGuildData.IsApplicant {
|
||||||
bf.WriteUint16(0)
|
bf.WriteUint16(0x00)
|
||||||
} else if guild.LeaderCharID == s.charID {
|
} else if guild.LeaderCharID == s.charID {
|
||||||
bf.WriteUint16(1)
|
bf.WriteUint16(0x01)
|
||||||
} else {
|
} else {
|
||||||
bf.WriteUint16(2)
|
bf.WriteUint16(0x02)
|
||||||
}
|
}
|
||||||
|
|
||||||
bf.WriteUint32(uint32(guild.CreatedAt.Unix()))
|
bf.WriteUint32(uint32(guild.CreatedAt.Unix()))
|
||||||
if characterGuildData.JoinedAt.IsZero() {
|
bf.WriteUint32(characterJoinedAt)
|
||||||
bf.WriteInt32(-1)
|
|
||||||
} else {
|
|
||||||
bf.WriteInt32(int32(characterGuildData.JoinedAt.Unix()))
|
|
||||||
}
|
|
||||||
bf.WriteUint8(uint8(len(guildName)))
|
bf.WriteUint8(uint8(len(guildName)))
|
||||||
bf.WriteUint8(uint8(len(guildComment)))
|
bf.WriteUint8(uint8(len(guildComment)))
|
||||||
bf.WriteUint8(uint8(5)) // Length of unknown string below
|
bf.WriteUint8(uint8(5)) // Length of unknown string below
|
||||||
@@ -974,8 +1028,8 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint16(0) // Ignored
|
bf.WriteUint16(0) // Ignored
|
||||||
|
|
||||||
if guild.AllianceID > 0 {
|
if guild.AllianceID > 0 {
|
||||||
alliance := GetAllianceData(s, guild.AllianceID)
|
alliance, err := GetAllianceData(s, guild.AllianceID)
|
||||||
if alliance.ID == 0 {
|
if err != nil {
|
||||||
bf.WriteUint32(0) // Error, no alliance
|
bf.WriteUint32(0) // Error, no alliance
|
||||||
} else {
|
} else {
|
||||||
bf.WriteUint32(alliance.ID)
|
bf.WriteUint32(alliance.ID)
|
||||||
@@ -1035,8 +1089,10 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint32(0) // No alliance
|
bf.WriteUint32(0) // No alliance
|
||||||
}
|
}
|
||||||
|
|
||||||
applicants := GetGuildApplications(s, guild.ID)
|
applicants, err := GetGuildMembers(s, guild.ID, true)
|
||||||
if characterGuildData.CanRecruit() {
|
if err != nil || (characterGuildData != nil && !characterGuildData.CanRecruit()) {
|
||||||
|
bf.WriteUint16(0)
|
||||||
|
} else {
|
||||||
bf.WriteUint16(uint16(len(applicants)))
|
bf.WriteUint16(uint16(len(applicants)))
|
||||||
for _, applicant := range applicants {
|
for _, applicant := range applicants {
|
||||||
bf.WriteUint32(applicant.CharID)
|
bf.WriteUint32(applicant.CharID)
|
||||||
@@ -1045,8 +1101,6 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint16(applicant.GR)
|
bf.WriteUint16(applicant.GR)
|
||||||
ps.Uint8(bf, applicant.Name, true)
|
ps.Uint8(bf, applicant.Name, true)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
bf.WriteUint16(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type UnkGuildInfo struct {
|
type UnkGuildInfo struct {
|
||||||
@@ -1112,18 +1166,17 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfEnumerateGuild)
|
pkt := p.(*mhfpacket.MsgMhfEnumerateGuild)
|
||||||
|
|
||||||
var guilds []Guild
|
var guilds []*Guild
|
||||||
var alliances []GuildAlliance
|
var alliances []*GuildAlliance
|
||||||
var rows *sqlx.Rows
|
var rows *sqlx.Rows
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if pkt.Type <= 8 {
|
if pkt.Type <= 8 {
|
||||||
var tempGuilds []Guild
|
var tempGuilds []*Guild
|
||||||
rows, err = s.server.db.Queryx(guildInfoSelectQuery)
|
rows, err = s.server.db.Queryx(guildInfoSelectQuery)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var guild Guild
|
guild, err := buildGuildObjectFromDbResult(rows, err, s)
|
||||||
err = rows.StructScan(&guild)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -1131,26 +1184,26 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch pkt.Type {
|
switch pkt.Type {
|
||||||
case mhfpacket.EnumerateGuildTypeGuildName:
|
case mhfpacket.ENUMERATE_GUILD_TYPE_GUILD_NAME:
|
||||||
for _, guild := range tempGuilds {
|
for _, guild := range tempGuilds {
|
||||||
if strings.Contains(guild.Name, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())) {
|
if strings.Contains(guild.Name, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())) {
|
||||||
guilds = append(guilds, guild)
|
guilds = append(guilds, guild)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case mhfpacket.EnumerateGuildTypeLeaderName:
|
case mhfpacket.ENUMERATE_GUILD_TYPE_LEADER_NAME:
|
||||||
for _, guild := range tempGuilds {
|
for _, guild := range tempGuilds {
|
||||||
if strings.Contains(guild.LeaderName, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())) {
|
if strings.Contains(guild.LeaderName, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())) {
|
||||||
guilds = append(guilds, guild)
|
guilds = append(guilds, guild)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case mhfpacket.EnumerateGuildTypeLeaderId:
|
case mhfpacket.ENUMERATE_GUILD_TYPE_LEADER_ID:
|
||||||
CID := pkt.Data1.ReadUint32()
|
CID := pkt.Data1.ReadUint32()
|
||||||
for _, guild := range tempGuilds {
|
for _, guild := range tempGuilds {
|
||||||
if guild.LeaderCharID == CID {
|
if guild.LeaderCharID == CID {
|
||||||
guilds = append(guilds, guild)
|
guilds = append(guilds, guild)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case mhfpacket.EnumerateGuildTypeOrderMembers:
|
case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_MEMBERS:
|
||||||
if pkt.Sorting {
|
if pkt.Sorting {
|
||||||
sort.Slice(tempGuilds, func(i, j int) bool {
|
sort.Slice(tempGuilds, func(i, j int) bool {
|
||||||
return tempGuilds[i].MemberCount > tempGuilds[j].MemberCount
|
return tempGuilds[i].MemberCount > tempGuilds[j].MemberCount
|
||||||
@@ -1161,7 +1214,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
guilds = tempGuilds
|
guilds = tempGuilds
|
||||||
case mhfpacket.EnumerateGuildTypeOrderRegistration:
|
case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_REGISTRATION:
|
||||||
if pkt.Sorting {
|
if pkt.Sorting {
|
||||||
sort.Slice(tempGuilds, func(i, j int) bool {
|
sort.Slice(tempGuilds, func(i, j int) bool {
|
||||||
return tempGuilds[i].CreatedAt.Unix() > tempGuilds[j].CreatedAt.Unix()
|
return tempGuilds[i].CreatedAt.Unix() > tempGuilds[j].CreatedAt.Unix()
|
||||||
@@ -1172,7 +1225,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
guilds = tempGuilds
|
guilds = tempGuilds
|
||||||
case mhfpacket.EnumerateGuildTypeOrderRank:
|
case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_RANK:
|
||||||
if pkt.Sorting {
|
if pkt.Sorting {
|
||||||
sort.Slice(tempGuilds, func(i, j int) bool {
|
sort.Slice(tempGuilds, func(i, j int) bool {
|
||||||
return tempGuilds[i].RankRP > tempGuilds[j].RankRP
|
return tempGuilds[i].RankRP > tempGuilds[j].RankRP
|
||||||
@@ -1183,7 +1236,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
guilds = tempGuilds
|
guilds = tempGuilds
|
||||||
case mhfpacket.EnumerateGuildTypeMotto:
|
case mhfpacket.ENUMERATE_GUILD_TYPE_MOTTO:
|
||||||
mainMotto := uint8(pkt.Data1.ReadUint16())
|
mainMotto := uint8(pkt.Data1.ReadUint16())
|
||||||
subMotto := uint8(pkt.Data1.ReadUint16())
|
subMotto := uint8(pkt.Data1.ReadUint16())
|
||||||
for _, guild := range tempGuilds {
|
for _, guild := range tempGuilds {
|
||||||
@@ -1191,7 +1244,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
guilds = append(guilds, guild)
|
guilds = append(guilds, guild)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case mhfpacket.EnumerateGuildTypeRecruiting:
|
case mhfpacket.ENUMERATE_GUILD_TYPE_RECRUITING:
|
||||||
recruitingMotto := uint8(pkt.Data1.ReadUint16())
|
recruitingMotto := uint8(pkt.Data1.ReadUint16())
|
||||||
for _, guild := range tempGuilds {
|
for _, guild := range tempGuilds {
|
||||||
if guild.MainMotto == recruitingMotto {
|
if guild.MainMotto == recruitingMotto {
|
||||||
@@ -1202,39 +1255,35 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if pkt.Type > 8 {
|
if pkt.Type > 8 {
|
||||||
var tempAlliances []GuildAlliance
|
var tempAlliances []*GuildAlliance
|
||||||
rows, err = s.server.db.Queryx(allianceInfoSelectQuery)
|
rows, err = s.server.db.Queryx(allianceInfoSelectQuery)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var alliance GuildAlliance
|
alliance, _ := buildAllianceObjectFromDbResult(rows, err, s)
|
||||||
err = rows.StructScan(&alliance)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
tempAlliances = append(tempAlliances, alliance)
|
tempAlliances = append(tempAlliances, alliance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch pkt.Type {
|
switch pkt.Type {
|
||||||
case mhfpacket.EnumerateAllianceTypeAllianceName:
|
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ALLIANCE_NAME:
|
||||||
for _, alliance := range tempAlliances {
|
for _, alliance := range tempAlliances {
|
||||||
if strings.Contains(alliance.Name, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())) {
|
if strings.Contains(alliance.Name, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())) {
|
||||||
alliances = append(alliances, alliance)
|
alliances = append(alliances, alliance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case mhfpacket.EnumerateAllianceTypeLeaderName:
|
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_NAME:
|
||||||
for _, alliance := range tempAlliances {
|
for _, alliance := range tempAlliances {
|
||||||
if strings.Contains(alliance.ParentGuild.LeaderName, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())) {
|
if strings.Contains(alliance.ParentGuild.LeaderName, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())) {
|
||||||
alliances = append(alliances, alliance)
|
alliances = append(alliances, alliance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case mhfpacket.EnumerateAllianceTypeLeaderId:
|
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_ID:
|
||||||
CID := pkt.Data1.ReadUint32()
|
CID := pkt.Data1.ReadUint32()
|
||||||
for _, alliance := range tempAlliances {
|
for _, alliance := range tempAlliances {
|
||||||
if alliance.ParentGuild.LeaderCharID == CID {
|
if alliance.ParentGuild.LeaderCharID == CID {
|
||||||
alliances = append(alliances, alliance)
|
alliances = append(alliances, alliance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case mhfpacket.EnumerateAllianceTypeOrderMembers:
|
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_MEMBERS:
|
||||||
if pkt.Sorting {
|
if pkt.Sorting {
|
||||||
sort.Slice(tempAlliances, func(i, j int) bool {
|
sort.Slice(tempAlliances, func(i, j int) bool {
|
||||||
return tempAlliances[i].TotalMembers > tempAlliances[j].TotalMembers
|
return tempAlliances[i].TotalMembers > tempAlliances[j].TotalMembers
|
||||||
@@ -1245,7 +1294,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
alliances = tempAlliances
|
alliances = tempAlliances
|
||||||
case mhfpacket.EnumerateAllianceTypeOrderRegistration:
|
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_REGISTRATION:
|
||||||
if pkt.Sorting {
|
if pkt.Sorting {
|
||||||
sort.Slice(tempAlliances, func(i, j int) bool {
|
sort.Slice(tempAlliances, func(i, j int) bool {
|
||||||
return tempAlliances[i].CreatedAt.Unix() > tempAlliances[j].CreatedAt.Unix()
|
return tempAlliances[i].CreatedAt.Unix() > tempAlliances[j].CreatedAt.Unix()
|
||||||
@@ -1320,13 +1369,26 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfArrangeGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfArrangeGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfArrangeGuildMember)
|
pkt := p.(*mhfpacket.MsgMhfArrangeGuildMember)
|
||||||
|
|
||||||
guild := GetGuildInfoByID(s, pkt.GuildID)
|
guild, err := GetGuildInfoByID(s, pkt.GuildID)
|
||||||
if guild.ID == 0 {
|
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
if err != nil {
|
||||||
|
s.logger.Error(
|
||||||
|
"failed to respond to ArrangeGuildMember message",
|
||||||
|
zap.Uint32("charID", s.charID),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := guild.ArrangeCharacters(s, pkt.CharIDs)
|
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 {
|
if err != nil {
|
||||||
s.logger.Error(
|
s.logger.Error(
|
||||||
"failed to respond to ArrangeGuildMember message",
|
"failed to respond to ArrangeGuildMember message",
|
||||||
@@ -1342,29 +1404,47 @@ func handleMsgMhfArrangeGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfEnumerateGuildMember)
|
pkt := p.(*mhfpacket.MsgMhfEnumerateGuildMember)
|
||||||
|
|
||||||
var guild Guild
|
var guild *Guild
|
||||||
|
var err error
|
||||||
|
|
||||||
if pkt.GuildID > 0 {
|
if pkt.GuildID > 0 {
|
||||||
guild = GetGuildInfoByID(s, pkt.GuildID)
|
guild, err = GetGuildInfoByID(s, pkt.GuildID)
|
||||||
} else {
|
} else {
|
||||||
guild = GetGuildInfoByCharacterId(s, s.charID)
|
guild, err = GetGuildInfoByCharacterId(s, s.charID)
|
||||||
}
|
}
|
||||||
if guild.ID == 0 && s.prevGuildID > 0 {
|
|
||||||
guild = GetGuildInfoByID(s, s.prevGuildID)
|
if guild != nil {
|
||||||
|
isApplicant, _ := guild.HasApplicationForCharID(s, s.charID)
|
||||||
|
if isApplicant {
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if guild.ID == 0 {
|
|
||||||
s.logger.Warn("failed to get guild")
|
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))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guildMembers := GetGuildMembers(s, guild.ID)
|
guildMembers, err := GetGuildMembers(s, guild.ID, false)
|
||||||
if len(guildMembers) == 0 {
|
|
||||||
s.logger.Error("failed to get guild members")
|
if err != nil {
|
||||||
|
s.logger.Error("failed to retrieve guild")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
alliance := GetAllianceData(s, guild.AllianceID)
|
alliance, err := GetAllianceData(s, guild.AllianceID)
|
||||||
if alliance.ID == 0 {
|
if err != nil {
|
||||||
s.logger.Error("failed to get alliance data")
|
s.logger.Error("Failed to get alliance data")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
@@ -1401,30 +1481,37 @@ func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint32(member.LastLogin)
|
bf.WriteUint32(member.LastLogin)
|
||||||
}
|
}
|
||||||
|
|
||||||
var allianceMembers []GuildMember
|
|
||||||
if guild.AllianceID > 0 {
|
if guild.AllianceID > 0 {
|
||||||
|
bf.WriteUint16(alliance.TotalMembers - uint16(len(guildMembers)))
|
||||||
if guild.ID != alliance.ParentGuildID {
|
if guild.ID != alliance.ParentGuildID {
|
||||||
members := GetGuildMembers(s, alliance.ParentGuildID)
|
mems, err := GetGuildMembers(s, alliance.ParentGuildID, false)
|
||||||
for i := range members {
|
if err != nil {
|
||||||
allianceMembers = append(allianceMembers, members[i])
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, m := range mems {
|
||||||
|
bf.WriteUint32(m.CharID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if guild.ID != alliance.SubGuild1ID {
|
if guild.ID != alliance.SubGuild1ID {
|
||||||
members := GetGuildMembers(s, alliance.SubGuild1ID)
|
mems, err := GetGuildMembers(s, alliance.SubGuild1ID, false)
|
||||||
for i := range members {
|
if err != nil {
|
||||||
allianceMembers = append(allianceMembers, members[i])
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, m := range mems {
|
||||||
|
bf.WriteUint32(m.CharID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if guild.ID != alliance.SubGuild2ID {
|
if guild.ID != alliance.SubGuild2ID {
|
||||||
members := GetGuildMembers(s, alliance.SubGuild2ID)
|
mems, err := GetGuildMembers(s, alliance.SubGuild2ID, false)
|
||||||
for i := range members {
|
if err != nil {
|
||||||
allianceMembers = append(allianceMembers, members[i])
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, m := range mems {
|
||||||
|
bf.WriteUint32(m.CharID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
bf.WriteUint16(uint16(len(allianceMembers)))
|
bf.WriteUint16(0)
|
||||||
for i := range allianceMembers {
|
|
||||||
bf.WriteUint32(allianceMembers[i].CharID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, member := range guildMembers {
|
for _, member := range guildMembers {
|
||||||
@@ -1438,27 +1525,23 @@ func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfGetGuildManageRight(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetGuildManageRight(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetGuildManageRight)
|
pkt := p.(*mhfpacket.MsgMhfGetGuildManageRight)
|
||||||
|
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if guild.ID == 0 && s.prevGuildID != 0 {
|
if guild == nil && s.prevGuildID != 0 {
|
||||||
guild = GetGuildInfoByID(s, s.prevGuildID)
|
guild, err = GetGuildInfoByID(s, s.prevGuildID)
|
||||||
s.prevGuildID = 0
|
s.prevGuildID = 0
|
||||||
if guild.ID == 0 {
|
if guild == nil || err != nil {
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
members := GetGuildMembers(s, guild.ID)
|
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
if members != nil {
|
bf.WriteUint32(uint32(guild.MemberCount))
|
||||||
bf.WriteUint32(uint32(len(members)))
|
members, _ := GetGuildMembers(s, guild.ID, false)
|
||||||
for _, member := range members {
|
for _, member := range members {
|
||||||
bf.WriteUint32(member.CharID)
|
bf.WriteUint32(member.CharID)
|
||||||
bf.WriteBool(member.Recruiter)
|
bf.WriteBool(member.Recruiter)
|
||||||
bf.WriteBytes(make([]byte, 3))
|
bf.WriteBytes(make([]byte, 3))
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bf.WriteUint32(0)
|
|
||||||
}
|
}
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
@@ -1471,23 +1554,25 @@ func handleMsgMhfGetUdGuildMapInfo(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfGetGuildTargetMemberNum(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetGuildTargetMemberNum(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetGuildTargetMemberNum)
|
pkt := p.(*mhfpacket.MsgMhfGetGuildTargetMemberNum)
|
||||||
|
|
||||||
var guild Guild
|
var guild *Guild
|
||||||
if pkt.GuildID == 0 {
|
var err error
|
||||||
guild = GetGuildInfoByCharacterId(s, s.charID)
|
|
||||||
|
if pkt.GuildID == 0x0 {
|
||||||
|
guild, err = GetGuildInfoByCharacterId(s, s.charID)
|
||||||
} else {
|
} else {
|
||||||
guild = GetGuildInfoByID(s, pkt.GuildID)
|
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 := byteframe.NewByteFrame()
|
||||||
|
|
||||||
if guild.ID == 0 {
|
bf.WriteUint16(0x0)
|
||||||
bf.WriteUint32(2)
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bf.WriteUint16(0)
|
|
||||||
bf.WriteUint16(guild.MemberCount - 1)
|
bf.WriteUint16(guild.MemberCount - 1)
|
||||||
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1524,14 +1609,32 @@ func handleMsgMhfUpdateGuildItem(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfUpdateGuildIcon(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfUpdateGuildIcon(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfUpdateGuildIcon)
|
pkt := p.(*mhfpacket.MsgMhfUpdateGuildIcon)
|
||||||
|
|
||||||
guild := GetGuildInfoByID(s, pkt.GuildID)
|
guild, err := GetGuildInfoByID(s, pkt.GuildID)
|
||||||
if guild.ID == 0 {
|
|
||||||
|
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))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
icon := &GuildIcon{}
|
icon := &GuildIcon{}
|
||||||
|
|
||||||
icon.Parts = make([]GuildIconPart, len(pkt.IconParts))
|
icon.Parts = make([]GuildIconPart, len(pkt.IconParts))
|
||||||
|
|
||||||
for i, p := range pkt.IconParts {
|
for i, p := range pkt.IconParts {
|
||||||
icon.Parts[i] = GuildIconPart{
|
icon.Parts[i] = GuildIconPart{
|
||||||
Index: p.Index,
|
Index: p.Index,
|
||||||
@@ -1549,7 +1652,7 @@ func handleMsgMhfUpdateGuildIcon(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
guild.Icon = icon
|
guild.Icon = icon
|
||||||
|
|
||||||
err := guild.Save(s)
|
err = guild.Save(s)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
@@ -1653,7 +1756,7 @@ type GuildMeal struct {
|
|||||||
|
|
||||||
func handleMsgMhfLoadGuildCooking(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfLoadGuildCooking(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfLoadGuildCooking)
|
pkt := p.(*mhfpacket.MsgMhfLoadGuildCooking)
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
data, err := s.server.db.Queryx("SELECT id, meal_id, level, created_at FROM guild_meals WHERE guild_id = $1", guild.ID)
|
data, err := s.server.db.Queryx("SELECT id, meal_id, level, created_at FROM guild_meals WHERE guild_id = $1", guild.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get guild meals from db", zap.Error(err))
|
s.logger.Error("Failed to get guild meals from db", zap.Error(err))
|
||||||
@@ -1684,7 +1787,7 @@ func handleMsgMhfLoadGuildCooking(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfRegistGuildCooking(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfRegistGuildCooking(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfRegistGuildCooking)
|
pkt := p.(*mhfpacket.MsgMhfRegistGuildCooking)
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
startTime := TimeAdjusted().Add(time.Duration(s.server.erupeConfig.GameplayOptions.ClanMealDuration-3600) * time.Second)
|
startTime := TimeAdjusted().Add(time.Duration(s.server.erupeConfig.GameplayOptions.ClanMealDuration-3600) * time.Second)
|
||||||
if pkt.OverwriteID != 0 {
|
if pkt.OverwriteID != 0 {
|
||||||
s.server.db.Exec("UPDATE guild_meals SET meal_id = $1, level = $2, created_at = $3 WHERE id = $4", pkt.MealID, pkt.Success, startTime, pkt.OverwriteID)
|
s.server.db.Exec("UPDATE guild_meals SET meal_id = $1, level = $2, created_at = $3 WHERE id = $4", pkt.MealID, pkt.Success, startTime, pkt.OverwriteID)
|
||||||
@@ -1749,10 +1852,10 @@ func handleMsgMhfGuildHuntdata(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint8(count)
|
bf.WriteUint8(count)
|
||||||
}
|
}
|
||||||
case 2: // Check
|
case 2: // Check
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if guild.ID > 0 {
|
if err == nil {
|
||||||
var count uint8
|
var count uint8
|
||||||
err := s.server.db.QueryRow(`SELECT COUNT(*) FROM kill_logs kl
|
err = s.server.db.QueryRow(`SELECT COUNT(*) FROM kill_logs kl
|
||||||
INNER JOIN guild_characters gc ON kl.character_id = gc.character_id
|
INNER JOIN guild_characters gc ON kl.character_id = gc.character_id
|
||||||
WHERE gc.guild_id=$1
|
WHERE gc.guild_id=$1
|
||||||
AND kl.timestamp >= (SELECT box_claimed FROM guild_characters WHERE character_id=$2)
|
AND kl.timestamp >= (SELECT box_claimed FROM guild_characters WHERE character_id=$2)
|
||||||
@@ -1781,13 +1884,13 @@ type MessageBoardPost struct {
|
|||||||
|
|
||||||
func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfEnumerateGuildMessageBoard)
|
pkt := p.(*mhfpacket.MsgMhfEnumerateGuildMessageBoard)
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if pkt.BoardType == 1 {
|
if pkt.BoardType == 1 {
|
||||||
pkt.MaxPosts = 4
|
pkt.MaxPosts = 4
|
||||||
}
|
}
|
||||||
msgs, err := s.server.db.Queryx("SELECT id, stamp_id, title, body, author_id, created_at, liked_by FROM guild_posts WHERE guild_id = $1 AND post_type = $2 ORDER BY created_at DESC", guild.ID, int(pkt.BoardType))
|
msgs, err := s.server.db.Queryx("SELECT id, stamp_id, title, body, author_id, created_at, liked_by FROM guild_posts WHERE guild_id = $1 AND post_type = $2 ORDER BY created_at DESC", guild.ID, int(pkt.BoardType))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("failed to get guild messages from db", zap.Error(err))
|
s.logger.Error("Failed to get guild messages from db", zap.Error(err))
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1819,8 +1922,12 @@ func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfUpdateGuildMessageBoard)
|
pkt := p.(*mhfpacket.MsgMhfUpdateGuildMessageBoard)
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if guild.ID == 0 || IsGuildApplicant(s, s.charID) {
|
applicant := false
|
||||||
|
if guild != nil {
|
||||||
|
applicant, _ = guild.HasApplicationForCharID(s, s.charID)
|
||||||
|
}
|
||||||
|
if err != nil || guild == nil || applicant {
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1904,13 +2011,12 @@ func handleMsgMhfAcquireMonthlyItem(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfEnumerateInvGuild(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEnumerateInvGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfEnumerateInvGuild)
|
pkt := p.(*mhfpacket.MsgMhfEnumerateInvGuild)
|
||||||
bf := byteframe.NewByteFrame()
|
stubEnumerateNoResults(s, pkt.AckHandle)
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfOperationInvGuild(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfOperationInvGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfOperationInvGuild)
|
pkt := p.(*mhfpacket.MsgMhfOperationInvGuild)
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfUpdateGuildcard(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfUpdateGuildcard(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ type GuildAdventure struct {
|
|||||||
|
|
||||||
func handleMsgMhfLoadGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfLoadGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfLoadGuildAdventure)
|
pkt := p.(*mhfpacket.MsgMhfLoadGuildAdventure)
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
data, err := s.server.db.Queryx("SELECT id, destination, charge, depart, return, collected_by FROM guild_adventures WHERE guild_id = $1", guild.ID)
|
data, err := s.server.db.Queryx("SELECT id, destination, charge, depart, return, collected_by FROM guild_adventures WHERE guild_id = $1", guild.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get guild adventures from db", zap.Error(err))
|
s.logger.Error("Failed to get guild adventures from db", zap.Error(err))
|
||||||
@@ -51,7 +51,7 @@ func handleMsgMhfLoadGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfRegistGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfRegistGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfRegistGuildAdventure)
|
pkt := p.(*mhfpacket.MsgMhfRegistGuildAdventure)
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
_, err := s.server.db.Exec("INSERT INTO guild_adventures (guild_id, destination, depart, return) VALUES ($1, $2, $3, $4)", guild.ID, pkt.Destination, TimeAdjusted().Unix(), TimeAdjusted().Add(6*time.Hour).Unix())
|
_, err := s.server.db.Exec("INSERT INTO guild_adventures (guild_id, destination, depart, return) VALUES ($1, $2, $3, $4)", guild.ID, pkt.Destination, TimeAdjusted().Unix(), TimeAdjusted().Add(6*time.Hour).Unix())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to register guild adventure", zap.Error(err))
|
s.logger.Error("Failed to register guild adventure", zap.Error(err))
|
||||||
@@ -86,7 +86,7 @@ func handleMsgMhfChargeGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfRegistGuildAdventureDiva(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfRegistGuildAdventureDiva(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfRegistGuildAdventureDiva)
|
pkt := p.(*mhfpacket.MsgMhfRegistGuildAdventureDiva)
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
_, err := s.server.db.Exec("INSERT INTO guild_adventures (guild_id, destination, charge, depart, return) VALUES ($1, $2, $3, $4, $5)", guild.ID, pkt.Destination, pkt.Charge, TimeAdjusted().Unix(), TimeAdjusted().Add(1*time.Hour).Unix())
|
_, err := s.server.db.Exec("INSERT INTO guild_adventures (guild_id, destination, charge, depart, return) VALUES ($1, $2, $3, $4, $5)", guild.ID, pkt.Destination, pkt.Charge, TimeAdjusted().Unix(), TimeAdjusted().Add(1*time.Hour).Unix())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to register guild adventure", zap.Error(err))
|
s.logger.Error("Failed to register guild adventure", zap.Error(err))
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -42,36 +43,66 @@ type GuildAlliance struct {
|
|||||||
SubGuild2 Guild
|
SubGuild2 Guild
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllianceData(s *Session, AllianceID uint32) GuildAlliance {
|
func GetAllianceData(s *Session, AllianceID uint32) (*GuildAlliance, error) {
|
||||||
var alliance GuildAlliance
|
rows, err := s.server.db.Queryx(fmt.Sprintf(`
|
||||||
err := s.server.db.QueryRowx(fmt.Sprintf(`
|
|
||||||
%s
|
%s
|
||||||
WHERE ga.id = $1
|
WHERE ga.id = $1
|
||||||
`, allianceInfoSelectQuery), AllianceID).StructScan(&alliance)
|
`, allianceInfoSelectQuery), AllianceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("failed to retrieve alliance data", zap.Error(err))
|
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.Error("Failed to get parent guild info", zap.Error(err))
|
||||||
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
parentGuild := GetGuildInfoByID(s, alliance.ParentGuildID)
|
alliance.ParentGuild = *parentGuild
|
||||||
if parentGuild.ID > 0 {
|
alliance.TotalMembers += parentGuild.MemberCount
|
||||||
alliance.ParentGuild = parentGuild
|
}
|
||||||
alliance.TotalMembers += parentGuild.MemberCount
|
|
||||||
}
|
if alliance.SubGuild1ID > 0 {
|
||||||
if alliance.SubGuild1ID > 0 {
|
subGuild1, err := GetGuildInfoByID(s, alliance.SubGuild1ID)
|
||||||
subGuild1 := GetGuildInfoByID(s, alliance.SubGuild1ID)
|
if err != nil {
|
||||||
if subGuild1.ID > 0 {
|
s.logger.Error("Failed to get sub guild 1 info", zap.Error(err))
|
||||||
alliance.SubGuild1 = subGuild1
|
return nil, err
|
||||||
alliance.TotalMembers += subGuild1.MemberCount
|
} else {
|
||||||
}
|
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
|
|
||||||
|
if alliance.SubGuild2ID > 0 {
|
||||||
|
subGuild2, err := GetGuildInfoByID(s, alliance.SubGuild2ID)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to get sub guild 2 info", zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
alliance.SubGuild2 = *subGuild2
|
||||||
|
alliance.TotalMembers += subGuild2.MemberCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return alliance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfCreateJoint(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfCreateJoint(s *Session, p mhfpacket.MHFPacket) {
|
||||||
@@ -86,19 +117,19 @@ func handleMsgMhfCreateJoint(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfOperateJoint)
|
pkt := p.(*mhfpacket.MsgMhfOperateJoint)
|
||||||
|
|
||||||
guild := GetGuildInfoByID(s, pkt.GuildID)
|
guild, err := GetGuildInfoByID(s, pkt.GuildID)
|
||||||
if guild.ID == 0 {
|
if err != nil {
|
||||||
s.logger.Error("failed to get guild info")
|
s.logger.Error("Failed to get guild info", zap.Error(err))
|
||||||
}
|
}
|
||||||
alliance := GetAllianceData(s, pkt.AllianceID)
|
alliance, err := GetAllianceData(s, pkt.AllianceID)
|
||||||
if alliance.ID == 0 {
|
if err != nil {
|
||||||
s.logger.Error("failed to get alliance info")
|
s.logger.Error("Failed to get alliance info", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch pkt.Action {
|
switch pkt.Action {
|
||||||
case mhfpacket.OperateJointDisband:
|
case mhfpacket.OPERATE_JOINT_DISBAND:
|
||||||
if guild.LeaderCharID == s.charID && alliance.ParentGuildID == guild.ID {
|
if guild.LeaderCharID == s.charID && alliance.ParentGuildID == guild.ID {
|
||||||
_, err := s.server.db.Exec("DELETE FROM guild_alliances WHERE id=$1", alliance.ID)
|
_, err = s.server.db.Exec("DELETE FROM guild_alliances WHERE id=$1", alliance.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to disband alliance", zap.Error(err))
|
s.logger.Error("Failed to disband alliance", zap.Error(err))
|
||||||
}
|
}
|
||||||
@@ -111,7 +142,7 @@ func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
)
|
)
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
}
|
}
|
||||||
case mhfpacket.OperateJointLeave:
|
case mhfpacket.OPERATE_JOINT_LEAVE:
|
||||||
if guild.LeaderCharID == s.charID {
|
if guild.LeaderCharID == s.charID {
|
||||||
if guild.ID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 {
|
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)
|
s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID)
|
||||||
@@ -129,7 +160,7 @@ func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
)
|
)
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
}
|
}
|
||||||
case mhfpacket.OperateJointKick:
|
case mhfpacket.OPERATE_JOINT_KICK:
|
||||||
if alliance.ParentGuild.LeaderCharID == s.charID {
|
if alliance.ParentGuild.LeaderCharID == s.charID {
|
||||||
kickedGuildID := pkt.Data1.ReadUint32()
|
kickedGuildID := pkt.Data1.ReadUint32()
|
||||||
if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 {
|
if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 {
|
||||||
@@ -157,8 +188,8 @@ func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfInfoJoint)
|
pkt := p.(*mhfpacket.MsgMhfInfoJoint)
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
alliance := GetAllianceData(s, pkt.AllianceID)
|
alliance, err := GetAllianceData(s, pkt.AllianceID)
|
||||||
if alliance.ID == 0 {
|
if err != nil {
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
} else {
|
} else {
|
||||||
bf.WriteUint32(alliance.ID)
|
bf.WriteUint32(alliance.ID)
|
||||||
|
|||||||
@@ -4,44 +4,49 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GuildMember struct {
|
type GuildMember struct {
|
||||||
GuildID uint32 `db:"guild_id"`
|
GuildID uint32 `db:"guild_id"`
|
||||||
CharID uint32 `db:"character_id"`
|
CharID uint32 `db:"character_id"`
|
||||||
JoinedAt time.Time `db:"joined_at"`
|
JoinedAt *time.Time `db:"joined_at"`
|
||||||
Souls uint32 `db:"souls"`
|
Souls uint32 `db:"souls"`
|
||||||
RPToday uint16 `db:"rp_today"`
|
RPToday uint16 `db:"rp_today"`
|
||||||
RPYesterday uint16 `db:"rp_yesterday"`
|
RPYesterday uint16 `db:"rp_yesterday"`
|
||||||
Name string `db:"name"`
|
Name string `db:"name"`
|
||||||
OrderIndex uint16 `db:"order_index"`
|
IsApplicant bool `db:"is_applicant"`
|
||||||
LastLogin uint32 `db:"last_login"`
|
OrderIndex uint16 `db:"order_index"`
|
||||||
Recruiter bool `db:"recruiter"`
|
LastLogin uint32 `db:"last_login"`
|
||||||
AvoidLeadership bool `db:"avoid_leadership"`
|
Recruiter bool `db:"recruiter"`
|
||||||
HR uint16 `db:"hr"`
|
AvoidLeadership bool `db:"avoid_leadership"`
|
||||||
GR uint16 `db:"gr"`
|
IsLeader bool `db:"is_leader"`
|
||||||
WeaponID uint16 `db:"weapon_id"`
|
HR uint16 `db:"hr"`
|
||||||
WeaponType uint8 `db:"weapon_type"`
|
GR uint16 `db:"gr"`
|
||||||
|
WeaponID uint16 `db:"weapon_id"`
|
||||||
|
WeaponType uint8 `db:"weapon_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gm GuildMember) CanRecruit() bool {
|
func (gm *GuildMember) CanRecruit() bool {
|
||||||
if gm.Recruiter {
|
if gm.Recruiter {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return gm.IsSubLeader()
|
if gm.OrderIndex <= 3 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if gm.IsLeader {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gm GuildMember) IsSubLeader() bool {
|
func (gm *GuildMember) IsSubLeader() bool {
|
||||||
return gm.OrderIndex <= 3
|
return gm.OrderIndex <= 3
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gm GuildMember) IsLeader() bool {
|
func (gm *GuildMember) Save(s *Session) error {
|
||||||
return gm.OrderIndex == 1
|
_, err := s.server.db.Exec("UPDATE guild_characters SET avoid_leadership=$1, order_index=$2 WHERE character_id=$3", gm.AvoidLeadership, gm.OrderIndex, gm.CharID)
|
||||||
}
|
|
||||||
|
|
||||||
func (gm GuildMember) Save(s *Session) error {
|
|
||||||
_, err := s.server.db.Exec("UPDATE guild_characters SET order_index=$1 WHERE character_id=$2", gm.OrderIndex, gm.CharID)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error(
|
s.logger.Error(
|
||||||
@@ -56,6 +61,7 @@ func (gm GuildMember) Save(s *Session) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const guildMembersSelectSQL = `
|
const guildMembersSelectSQL = `
|
||||||
|
SELECT * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
g.id AS guild_id,
|
g.id AS guild_id,
|
||||||
joined_at,
|
joined_at,
|
||||||
@@ -71,71 +77,71 @@ const guildMembersSelectSQL = `
|
|||||||
c.hr,
|
c.hr,
|
||||||
c.gr,
|
c.gr,
|
||||||
c.weapon_id,
|
c.weapon_id,
|
||||||
c.weapon_type
|
c.weapon_type,
|
||||||
|
EXISTS(SELECT 1 FROM guild_applications ga WHERE ga.character_id=c.id AND application_type='applied') AS is_applicant,
|
||||||
|
CASE WHEN g.leader_id = c.id THEN true ELSE false END AS is_leader
|
||||||
FROM guild_characters gc
|
FROM guild_characters gc
|
||||||
LEFT JOIN characters c ON c.id = gc.character_id
|
LEFT JOIN characters c ON c.id = gc.character_id
|
||||||
LEFT JOIN guilds g ON g.id = gc.guild_id
|
LEFT JOIN guilds g ON g.id = gc.guild_id
|
||||||
|
) AS subquery
|
||||||
`
|
`
|
||||||
|
|
||||||
func GetGuildApplications(s *Session, guildID uint32) []GuildApplication {
|
func GetGuildMembers(s *Session, guildID uint32, applicants bool) ([]*GuildMember, error) {
|
||||||
var applications []GuildApplication
|
|
||||||
var application GuildApplication
|
|
||||||
rows, err := s.server.db.Queryx(`SELECT ga.character_id, ga.created_at, c.hr, c.gr, c.name FROM guild_applications ga LEFT JOIN characters c ON c.id = ga.character_id WHERE ga.guild_id=$1`, guildID)
|
|
||||||
if err == nil {
|
|
||||||
for rows.Next() {
|
|
||||||
err = rows.StructScan(&application)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
applications = append(applications, application)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return applications
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetGuildInvites(s *Session, guildID uint32) []GuildInvite {
|
|
||||||
var invites []GuildInvite
|
|
||||||
var invite GuildInvite
|
|
||||||
rows, err := s.server.db.Queryx(`SELECT gi.character_id, gi.id, gi.created_at, gi.actor_id, c.hr, c.gr, c.name FROM guild_invites gi LEFT JOIN characters c ON c.id = gi.character_id WHERE gi.guild_id=$1`, guildID)
|
|
||||||
if err == nil {
|
|
||||||
for rows.Next() {
|
|
||||||
err = rows.StructScan(&invite)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
invites = append(invites, invite)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return invites
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetGuildMembers(s *Session, guildID uint32) []GuildMember {
|
|
||||||
var members []GuildMember
|
|
||||||
var member GuildMember
|
|
||||||
rows, err := s.server.db.Queryx(fmt.Sprintf(`
|
rows, err := s.server.db.Queryx(fmt.Sprintf(`
|
||||||
%s
|
%s
|
||||||
WHERE guild_id = $1
|
WHERE guild_id = $1 AND is_applicant = $2
|
||||||
`, guildMembersSelectSQL), guildID)
|
`, guildMembersSelectSQL), guildID, applicants)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to retrieve membership data for guild", zap.Error(err), zap.Uint32("guildID", guildID))
|
s.logger.Error("failed to retrieve membership data for guild", zap.Error(err), zap.Uint32("guildID", guildID))
|
||||||
return members
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
members := make([]*GuildMember, 0)
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
err = rows.StructScan(&member)
|
member, err := buildGuildMemberObjectFromDBResult(rows, err, s)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
members = append(members, member)
|
members = append(members, member)
|
||||||
}
|
}
|
||||||
return members
|
|
||||||
|
return members, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCharacterGuildData(s *Session, charID uint32) GuildMember {
|
func GetCharacterGuildData(s *Session, charID uint32) (*GuildMember, error) {
|
||||||
var member GuildMember
|
rows, err := s.server.db.Queryx(fmt.Sprintf("%s WHERE character_id=$1", guildMembersSelectSQL), charID)
|
||||||
err := s.server.db.QueryRowx(fmt.Sprintf("%s WHERE character_id=$1", guildMembersSelectSQL), charID).StructScan(&member)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to retrieve membership data for character", zap.Error(err), zap.Uint32("charID", charID))
|
s.logger.Error(fmt.Sprintf("failed to retrieve membership data for character '%d'", charID))
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return member
|
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
hasRow := rows.Next()
|
||||||
|
|
||||||
|
if !hasRow {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildGuildMemberObjectFromDBResult(rows, err, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildGuildMemberObjectFromDBResult(rows *sqlx.Rows, err error, s *Session) (*GuildMember, error) {
|
||||||
|
memberData := &GuildMember{}
|
||||||
|
|
||||||
|
err = rows.StructScan(&memberData)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("failed to retrieve guild data from database", zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return memberData, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,18 +5,57 @@ import (
|
|||||||
"erupe-ce/common/stringsupport"
|
"erupe-ce/common/stringsupport"
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
func handleMsgMhfPostGuildScout(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfPostGuildScout(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfPostGuildScout)
|
pkt := p.(*mhfpacket.MsgMhfPostGuildScout)
|
||||||
|
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
actorCharGuildData, err := GetCharacterGuildData(s, s.charID)
|
||||||
if guild.ID == 0 {
|
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
if err != nil {
|
||||||
|
doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if actorCharGuildData == nil || !actorCharGuildData.CanRecruit() {
|
||||||
|
doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.server.db.Exec(`INSERT INTO guild_invites (guild_id, character_id, actor_id) VALUES ($1, $2, $3)`, s.charID, pkt.CharID, guild.ID)
|
guildInfo, err := GetGuildInfoByID(s, actorCharGuildData.GuildID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hasApplication, err := guildInfo.HasApplicationForCharID(s, pkt.CharID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasApplication {
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x04})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction, err := s.server.db.Begin()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = guildInfo.CreateApplication(s, pkt.CharID, GuildApplicationTypeInvited, transaction)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
rollbackTransaction(s, transaction)
|
||||||
|
doAckBufFail(s, pkt.AckHandle, nil)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
mail := &Mail{
|
mail := &Mail{
|
||||||
SenderID: s.charID,
|
SenderID: s.charID,
|
||||||
@@ -24,33 +63,85 @@ func handleMsgMhfPostGuildScout(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
Subject: s.server.i18n.guild.invite.title,
|
Subject: s.server.i18n.guild.invite.title,
|
||||||
Body: fmt.Sprintf(
|
Body: fmt.Sprintf(
|
||||||
s.server.i18n.guild.invite.body,
|
s.server.i18n.guild.invite.body,
|
||||||
guild.Name,
|
guildInfo.Name,
|
||||||
),
|
),
|
||||||
IsGuildInvite: true,
|
IsGuildInvite: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
mail.Send(s)
|
err = mail.Send(s, transaction)
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
|
||||||
|
if err != nil {
|
||||||
|
rollbackTransaction(s, transaction)
|
||||||
|
doAckBufFail(s, pkt.AckHandle, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = transaction.Commit()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
doAckBufFail(s, pkt.AckHandle, nil)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfCancelGuildScout(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfCancelGuildScout(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfCancelGuildScout)
|
pkt := p.(*mhfpacket.MsgMhfCancelGuildScout)
|
||||||
s.server.db.Exec(`DELETE FROM guild_invites WHERE id=$1`, pkt.InvitationID)
|
|
||||||
|
guildCharData, err := GetCharacterGuildData(s, s.charID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if guildCharData == nil || !guildCharData.CanRecruit() {
|
||||||
|
doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guild, err := GetGuildInfoByID(s, guildCharData.GuildID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = guild.CancelInvitation(s, pkt.InvitationID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfAnswerGuildScout(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfAnswerGuildScout(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfAnswerGuildScout)
|
pkt := p.(*mhfpacket.MsgMhfAnswerGuildScout)
|
||||||
|
bf := byteframe.NewByteFrame()
|
||||||
|
guild, err := GetGuildInfoByCharacterId(s, pkt.LeaderID)
|
||||||
|
|
||||||
guild := GetGuildInfoByCharacterId(s, pkt.LeaderID)
|
if err != nil {
|
||||||
if guild.ID == 0 {
|
panic(err)
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
}
|
||||||
|
|
||||||
|
app, err := guild.GetApplicationForCharID(s, s.charID, GuildApplicationTypeInvited)
|
||||||
|
|
||||||
|
if app == nil || err != nil {
|
||||||
|
s.logger.Warn(
|
||||||
|
"Guild invite missing, deleted?",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Uint32("guildID", guild.ID),
|
||||||
|
zap.Uint32("charID", s.charID),
|
||||||
|
)
|
||||||
|
bf.WriteUint32(7)
|
||||||
|
bf.WriteUint32(guild.ID)
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bf := byteframe.NewByteFrame()
|
|
||||||
var mail []Mail
|
var mail []Mail
|
||||||
var err error
|
|
||||||
if pkt.Answer {
|
if pkt.Answer {
|
||||||
err = guild.AcceptApplication(s, s.charID)
|
err = guild.AcceptApplication(s, s.charID)
|
||||||
mail = append(mail, Mail{
|
mail = append(mail, Mail{
|
||||||
@@ -91,7 +182,7 @@ func handleMsgMhfAnswerGuildScout(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint32(guild.ID)
|
bf.WriteUint32(guild.ID)
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
for _, m := range mail {
|
for _, m := range mail {
|
||||||
m.Send(s)
|
m.Send(s, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,46 +190,121 @@ func handleMsgMhfAnswerGuildScout(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetGuildScoutList)
|
pkt := p.(*mhfpacket.MsgMhfGetGuildScoutList)
|
||||||
|
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guildInfo, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if guild.ID == 0 && s.prevGuildID == 0 {
|
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
if guildInfo == nil && s.prevGuildID == 0 {
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
guild = GetGuildInfoByID(s, s.prevGuildID)
|
guildInfo, err = GetGuildInfoByID(s, s.prevGuildID)
|
||||||
if guild.ID == 0 {
|
if guildInfo == nil || err != nil {
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
invites := GetGuildInvites(s, guild.ID)
|
rows, err := s.server.db.Queryx(`
|
||||||
bf := byteframe.NewByteFrame()
|
SELECT c.id, c.name, c.hr, c.gr, ga.actor_id
|
||||||
bf.WriteUint32(uint32(len(invites)))
|
FROM guild_applications ga
|
||||||
for _, invite := range invites {
|
JOIN characters c ON c.id = ga.character_id
|
||||||
bf.WriteUint32(invite.ID)
|
WHERE ga.guild_id = $1 AND ga.application_type = 'invited'
|
||||||
bf.WriteUint32(invite.ActorID)
|
`, guildInfo.ID)
|
||||||
bf.WriteUint32(invite.CharID)
|
|
||||||
bf.WriteUint32(uint32(invite.InvitedAt.Unix()))
|
if err != nil {
|
||||||
bf.WriteUint16(invite.HR)
|
s.logger.Error("failed to retrieve scouted characters", zap.Error(err))
|
||||||
bf.WriteUint16(invite.GR)
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
bf.WriteBytes(stringsupport.PaddedString(invite.Name, 32, true))
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
bf := byteframe.NewByteFrame()
|
||||||
|
|
||||||
|
bf.SetBE()
|
||||||
|
|
||||||
|
// Result count, we will overwrite this later
|
||||||
|
bf.WriteUint32(0x00)
|
||||||
|
|
||||||
|
count := uint32(0)
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var charName string
|
||||||
|
var charID, actorID uint32
|
||||||
|
var HR, GR uint16
|
||||||
|
|
||||||
|
err = rows.Scan(&charID, &charName, &HR, &GR, &actorID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
doAckSimpleFail(s, pkt.AckHandle, nil)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// This seems to be used as a unique ID for the invitation sent
|
||||||
|
// we can just use the charID and then filter on guild_id+charID when performing operations
|
||||||
|
// this might be a problem later with mails sent referencing IDs but we'll see.
|
||||||
|
bf.WriteUint32(charID)
|
||||||
|
bf.WriteUint32(actorID)
|
||||||
|
bf.WriteUint32(charID)
|
||||||
|
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||||
|
bf.WriteUint16(HR) // HR?
|
||||||
|
bf.WriteUint16(GR) // GR?
|
||||||
|
bf.WriteBytes(stringsupport.PaddedString(charName, 32, true))
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = bf.Seek(0, io.SeekStart)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bf.WriteUint32(count)
|
||||||
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfGetRejectGuildScout(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetRejectGuildScout(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetRejectGuildScout)
|
pkt := p.(*mhfpacket.MsgMhfGetRejectGuildScout)
|
||||||
|
|
||||||
|
row := s.server.db.QueryRow("SELECT restrict_guild_scout FROM characters WHERE id=$1", s.charID)
|
||||||
|
|
||||||
var currentStatus bool
|
var currentStatus bool
|
||||||
s.server.db.QueryRow(`SELECT restrict_guild_scout FROM characters WHERE id=$1`, s.charID).Scan(¤tStatus)
|
|
||||||
if currentStatus {
|
err := row.Scan(¤tStatus)
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01})
|
|
||||||
} else {
|
if err != nil {
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
s.logger.Error(
|
||||||
|
"failed to retrieve character guild scout status",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Uint32("charID", s.charID),
|
||||||
|
)
|
||||||
|
doAckSimpleFail(s, pkt.AckHandle, nil)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response := uint8(0x00)
|
||||||
|
|
||||||
|
if currentStatus {
|
||||||
|
response = 0x01
|
||||||
|
}
|
||||||
|
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, response})
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfSetRejectGuildScout(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfSetRejectGuildScout(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfSetRejectGuildScout)
|
pkt := p.(*mhfpacket.MsgMhfSetRejectGuildScout)
|
||||||
s.server.db.Exec(`UPDATE characters SET restrict_guild_scout=$1 WHERE id=$2`, pkt.Reject, s.charID)
|
|
||||||
|
_, err := s.server.db.Exec("UPDATE characters SET restrict_guild_scout=$1 WHERE id=$2", pkt.Reject, s.charID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error(
|
||||||
|
"failed to update character guild scout status",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Uint32("charID", s.charID),
|
||||||
|
)
|
||||||
|
doAckSimpleFail(s, pkt.AckHandle, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, nil)
|
doAckSimpleSucceed(s, pkt.AckHandle, nil)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ type TreasureHunt struct {
|
|||||||
|
|
||||||
func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfEnumerateGuildTresure)
|
pkt := p.(*mhfpacket.MsgMhfEnumerateGuildTresure)
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if guild.ID == 0 {
|
if err != nil || guild == nil {
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
switch pkt.MaxHunts {
|
switch pkt.MaxHunts {
|
||||||
case 1:
|
case 1:
|
||||||
err := s.server.db.QueryRowx(`SELECT id, host_id, destination, level, start, hunt_data FROM guild_hunts WHERE host_id=$1 AND acquired=FALSE`, s.charID).StructScan(&hunt)
|
err = s.server.db.QueryRowx(`SELECT id, host_id, destination, level, start, hunt_data FROM guild_hunts WHERE host_id=$1 AND acquired=FALSE`, s.charID).StructScan(&hunt)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
hunts = append(hunts, hunt)
|
hunts = append(hunts, hunt)
|
||||||
}
|
}
|
||||||
@@ -83,8 +83,8 @@ func handleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
pkt := p.(*mhfpacket.MsgMhfRegistGuildTresure)
|
pkt := p.(*mhfpacket.MsgMhfRegistGuildTresure)
|
||||||
bf := byteframe.NewByteFrameFromBytes(pkt.Data)
|
bf := byteframe.NewByteFrameFromBytes(pkt.Data)
|
||||||
huntData := byteframe.NewByteFrame()
|
huntData := byteframe.NewByteFrame()
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if guild.ID == 0 {
|
if err != nil || guild == nil {
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,18 +75,18 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if guild.ID == 0 {
|
if err != nil || guild == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
guildMembers := GetGuildMembers(s, guild.ID)
|
guildMembers, err := GetGuildMembers(s, guild.ID, false)
|
||||||
if len(guildMembers) == 0 {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
for _, member := range guildMembers {
|
for _, member := range guildMembers {
|
||||||
house := HouseData{}
|
house := HouseData{}
|
||||||
row := s.server.db.QueryRowx(houseQuery, member.CharID)
|
row := s.server.db.QueryRowx(houseQuery, member.CharID)
|
||||||
err := row.StructScan(&house)
|
err = row.StructScan(&house)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
houses = append(houses, house)
|
houses = append(houses, house)
|
||||||
}
|
}
|
||||||
@@ -176,11 +176,12 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
// Guild verification
|
// Guild verification
|
||||||
if state > 3 {
|
if state > 3 {
|
||||||
ownGuild := GetGuildInfoByCharacterId(s, s.charID)
|
ownGuild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if ownGuild.ID != 0 && !IsGuildApplicant(s, s.charID) {
|
isApplicant, _ := ownGuild.HasApplicationForCharID(s, s.charID)
|
||||||
othersGuild := GetGuildInfoByCharacterId(s, pkt.CharID)
|
if err == nil && ownGuild != nil {
|
||||||
if othersGuild.ID != 0 && !IsGuildApplicant(s, pkt.CharID) {
|
othersGuild, err := GetGuildInfoByCharacterId(s, pkt.CharID)
|
||||||
if othersGuild.ID == ownGuild.ID {
|
if err == nil && othersGuild != nil {
|
||||||
|
if othersGuild.ID == ownGuild.ID && !isApplicant {
|
||||||
allowed = true
|
allowed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,17 +367,13 @@ func handleMsgMhfAcquireTitle(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfResetTitle(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfResetTitle(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
func initializeWarehouse(s *Session) {
|
func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfOperateWarehouse)
|
||||||
var t int
|
var t int
|
||||||
err := s.server.db.QueryRow("SELECT character_id FROM warehouse WHERE character_id=$1", s.charID).Scan(&t)
|
err := s.server.db.QueryRow("SELECT character_id FROM warehouse WHERE character_id=$1", s.charID).Scan(&t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.server.db.Exec("INSERT INTO warehouse (character_id) VALUES ($1)", s.charID)
|
s.server.db.Exec("INSERT INTO warehouse (character_id) VALUES ($1)", s.charID)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {
|
|
||||||
pkt := p.(*mhfpacket.MsgMhfOperateWarehouse)
|
|
||||||
initializeWarehouse(s)
|
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bf.WriteUint8(pkt.Operation)
|
bf.WriteUint8(pkt.Operation)
|
||||||
switch pkt.Operation {
|
switch pkt.Operation {
|
||||||
@@ -449,7 +446,6 @@ func addWarehouseEquipment(s *Session, equipment mhfitem.MHFEquipment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func warehouseGetItems(s *Session, index uint8) []mhfitem.MHFItemStack {
|
func warehouseGetItems(s *Session, index uint8) []mhfitem.MHFItemStack {
|
||||||
initializeWarehouse(s)
|
|
||||||
var data []byte
|
var data []byte
|
||||||
var items []mhfitem.MHFItemStack
|
var items []mhfitem.MHFItemStack
|
||||||
s.server.db.QueryRow(fmt.Sprintf(`SELECT item%d FROM warehouse WHERE character_id=$1`, index), s.charID).Scan(&data)
|
s.server.db.QueryRow(fmt.Sprintf(`SELECT item%d FROM warehouse WHERE character_id=$1`, index), s.charID).Scan(&data)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package channelserver
|
package channelserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"erupe-ce/common/stringsupport"
|
"erupe-ce/common/stringsupport"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -28,16 +29,36 @@ type Mail struct {
|
|||||||
SenderName string `db:"sender_name"`
|
SenderName string `db:"sender_name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mail) Send(s *Session) error {
|
func (m *Mail) Send(s *Session, transaction *sql.Tx) error {
|
||||||
query := `
|
query := `
|
||||||
INSERT INTO mail (sender_id, recipient_id, subject, body, attached_item, attached_item_amount, is_guild_invite, is_sys_message)
|
INSERT INTO mail (sender_id, recipient_id, subject, body, attached_item, attached_item_amount, is_guild_invite, is_sys_message)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||||
`
|
`
|
||||||
_, err := s.server.db.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite, m.IsSystemMessage)
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if transaction == nil {
|
||||||
|
_, err = s.server.db.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite, m.IsSystemMessage)
|
||||||
|
} else {
|
||||||
|
_, err = transaction.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite, m.IsSystemMessage)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("failed to send mail", zap.Error(err))
|
s.logger.Error(
|
||||||
|
"failed to send mail",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Uint32("senderID", m.SenderID),
|
||||||
|
zap.Uint32("recipientID", m.RecipientID),
|
||||||
|
zap.String("subject", m.Subject),
|
||||||
|
zap.String("body", m.Body),
|
||||||
|
zap.Uint16("itemID", m.AttachedItemID),
|
||||||
|
zap.Uint16("itemAmount", m.AttachedItemAmount),
|
||||||
|
zap.Bool("isGuildInvite", m.IsGuildInvite),
|
||||||
|
zap.Bool("isSystemMessage", m.IsSystemMessage),
|
||||||
|
)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,9 +189,16 @@ func SendMailNotification(s *Session, m *Mail, recipient *Session) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getCharacterName(s *Session, charID uint32) string {
|
func getCharacterName(s *Session, charID uint32) string {
|
||||||
var name string
|
row := s.server.db.QueryRow("SELECT name FROM characters WHERE id = $1", charID)
|
||||||
s.server.db.QueryRow("SELECT name FROM characters WHERE id = $1", charID).Scan(&name)
|
|
||||||
return name
|
charName := ""
|
||||||
|
|
||||||
|
err := row.Scan(&charName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return charName
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) {
|
||||||
@@ -227,21 +255,26 @@ func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
msg.WriteUint8(accIndex)
|
msg.WriteUint8(accIndex)
|
||||||
msg.WriteUint8(uint8(i))
|
msg.WriteUint8(uint8(i))
|
||||||
|
|
||||||
var flags uint8
|
flags := uint8(0x00)
|
||||||
|
|
||||||
if m.Read {
|
if m.Read {
|
||||||
flags |= 1 << 0
|
flags |= 0x01
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.Locked {
|
if m.Locked {
|
||||||
flags |= 1 << 1
|
flags |= 0x02
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.IsSystemMessage {
|
if m.IsSystemMessage {
|
||||||
flags |= 1 << 2
|
flags |= 0x04
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.AttachedItemReceived {
|
if m.AttachedItemReceived {
|
||||||
flags |= 1 << 3
|
flags |= 0x08
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.IsGuildInvite {
|
if m.IsGuildInvite {
|
||||||
flags |= 1 << 4
|
flags |= 0x10
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.WriteUint8(flags)
|
msg.WriteUint8(flags)
|
||||||
@@ -289,20 +322,31 @@ func handleMsgMhfSendMail(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
`
|
`
|
||||||
|
|
||||||
if pkt.RecipientID == 0 { // Guild mail
|
if pkt.RecipientID == 0 { // Guild mail
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
g, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if guild.ID == 0 {
|
if err != nil {
|
||||||
s.logger.Error("failed to get guild info for mail")
|
s.logger.Error("Failed to get guild info for mail")
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guildMembers := GetGuildMembers(s, guild.ID)
|
gm, err := GetGuildMembers(s, g.ID, false)
|
||||||
if len(guildMembers) > 0 {
|
if err != nil {
|
||||||
for _, member := range guildMembers {
|
s.logger.Error("Failed to get guild members for mail")
|
||||||
s.server.db.Exec(query, s.charID, member.CharID, pkt.Subject, pkt.Body, 0, 0, false)
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := 0; i < len(gm); i++ {
|
||||||
|
_, err := s.server.db.Exec(query, s.charID, gm[i].CharID, pkt.Subject, pkt.Body, 0, 0, false)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to send mail")
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s.server.db.Exec(query, s.charID, pkt.RecipientID, pkt.Subject, pkt.Body, pkt.ItemID, pkt.Quantity, false)
|
_, err := s.server.db.Exec(query, s.charID, pkt.RecipientID, pkt.Subject, pkt.Body, pkt.ItemID, pkt.Quantity, false)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to send mail")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,60 +157,60 @@ func handleMsgMhfSaveMercenary(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfReadMercenaryW)
|
pkt := p.(*mhfpacket.MsgMhfReadMercenaryW)
|
||||||
bf := byteframe.NewByteFrame()
|
if pkt.Op > 0 {
|
||||||
|
bf := byteframe.NewByteFrame()
|
||||||
|
var pactID uint32
|
||||||
|
var name string
|
||||||
|
var cid uint32
|
||||||
|
|
||||||
var pactID, cid uint32
|
s.server.db.QueryRow("SELECT pact_id FROM characters WHERE id=$1", s.charID).Scan(&pactID)
|
||||||
var name string
|
if pactID > 0 {
|
||||||
s.server.db.QueryRow("SELECT pact_id FROM characters WHERE id=$1", s.charID).Scan(&pactID)
|
s.server.db.QueryRow("SELECT name, id FROM characters WHERE rasta_id = $1", pactID).Scan(&name, &cid)
|
||||||
if pactID > 0 {
|
bf.WriteUint8(1) // numLends
|
||||||
s.server.db.QueryRow("SELECT name, id FROM characters WHERE rasta_id = $1", pactID).Scan(&name, &cid)
|
bf.WriteUint32(pactID)
|
||||||
bf.WriteUint8(1) // numLends
|
bf.WriteUint32(cid)
|
||||||
bf.WriteUint32(pactID)
|
bf.WriteBool(false) // ?
|
||||||
bf.WriteUint32(cid)
|
bf.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -8).Unix()))
|
||||||
bf.WriteBool(false) // ?
|
bf.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -1).Unix()))
|
||||||
bf.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -8).Unix()))
|
bf.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
||||||
bf.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -1).Unix()))
|
|
||||||
bf.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
|
||||||
} else {
|
|
||||||
bf.WriteUint8(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
var loans uint8
|
|
||||||
temp := byteframe.NewByteFrame()
|
|
||||||
if pkt.Op < 2 {
|
|
||||||
rows, _ := s.server.db.Query("SELECT name, id, pact_id FROM characters WHERE pact_id=(SELECT rasta_id FROM characters WHERE id=$1)", s.charID)
|
|
||||||
for rows.Next() {
|
|
||||||
err := rows.Scan(&name, &cid, &pactID)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
loans++
|
|
||||||
temp.WriteUint32(pactID)
|
|
||||||
temp.WriteUint32(cid)
|
|
||||||
temp.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -8).Unix()))
|
|
||||||
temp.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -1).Unix()))
|
|
||||||
temp.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bf.WriteUint8(loans)
|
|
||||||
bf.WriteBytes(temp.Data())
|
|
||||||
|
|
||||||
if pkt.Op < 1 {
|
|
||||||
var data []byte
|
|
||||||
var gcp uint32
|
|
||||||
s.server.db.QueryRow("SELECT savemercenary FROM characters WHERE id=$1", s.charID).Scan(&data)
|
|
||||||
s.server.db.QueryRow("SELECT COALESCE(gcp, 0) FROM characters WHERE id=$1", s.charID).Scan(&gcp)
|
|
||||||
|
|
||||||
if len(data) == 0 {
|
|
||||||
bf.WriteBool(false)
|
|
||||||
} else {
|
} else {
|
||||||
bf.WriteBool(true)
|
bf.WriteUint8(0)
|
||||||
bf.WriteBytes(data)
|
|
||||||
}
|
}
|
||||||
bf.WriteUint32(gcp)
|
|
||||||
}
|
|
||||||
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
if pkt.Op < 2 {
|
||||||
|
var loans uint8
|
||||||
|
temp := byteframe.NewByteFrame()
|
||||||
|
rows, _ := s.server.db.Query("SELECT name, id, pact_id FROM characters WHERE pact_id=(SELECT rasta_id FROM characters WHERE id=$1)", s.charID)
|
||||||
|
for rows.Next() {
|
||||||
|
loans++
|
||||||
|
rows.Scan(&name, &cid, &pactID)
|
||||||
|
temp.WriteUint32(pactID)
|
||||||
|
temp.WriteUint32(cid)
|
||||||
|
temp.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -8).Unix()))
|
||||||
|
temp.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -1).Unix()))
|
||||||
|
temp.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
||||||
|
}
|
||||||
|
bf.WriteUint8(loans)
|
||||||
|
bf.WriteBytes(temp.Data())
|
||||||
|
}
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var data []byte
|
||||||
|
var gcp uint32
|
||||||
|
s.server.db.QueryRow("SELECT savemercenary FROM characters WHERE id=$1", s.charID).Scan(&data)
|
||||||
|
s.server.db.QueryRow("SELECT COALESCE(gcp, 0) FROM characters WHERE id=$1", s.charID).Scan(&gcp)
|
||||||
|
|
||||||
|
resp := byteframe.NewByteFrame()
|
||||||
|
resp.WriteUint16(0)
|
||||||
|
if len(data) == 0 {
|
||||||
|
resp.WriteBool(false)
|
||||||
|
} else {
|
||||||
|
resp.WriteBool(true)
|
||||||
|
resp.WriteBytes(data)
|
||||||
|
}
|
||||||
|
resp.WriteUint32(gcp)
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfReadMercenaryM(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfReadMercenaryM(s *Session, p mhfpacket.MHFPacket) {
|
||||||
@@ -327,8 +327,8 @@ type Airou struct {
|
|||||||
func getGuildAirouList(s *Session) []Airou {
|
func getGuildAirouList(s *Session) []Airou {
|
||||||
var guildCats []Airou
|
var guildCats []Airou
|
||||||
bannedCats := make(map[uint32]int)
|
bannedCats := make(map[uint32]int)
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
if guild.ID == 0 {
|
if err != nil {
|
||||||
return guildCats
|
return guildCats
|
||||||
}
|
}
|
||||||
rows, err := s.server.db.Query(`SELECT cats_used FROM guild_hunts gh
|
rows, err := s.server.db.Query(`SELECT cats_used FROM guild_hunts gh
|
||||||
|
|||||||
@@ -111,9 +111,14 @@ type RengokuScore struct {
|
|||||||
func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfEnumerateRengokuRanking)
|
pkt := p.(*mhfpacket.MsgMhfEnumerateRengokuRanking)
|
||||||
|
|
||||||
guild := GetGuildInfoByCharacterId(s, s.charID)
|
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
|
isApplicant, _ := guild.HasApplicationForCharID(s, s.charID)
|
||||||
|
if isApplicant {
|
||||||
|
guild = nil
|
||||||
|
}
|
||||||
|
|
||||||
if pkt.Leaderboard == 2 || pkt.Leaderboard == 3 || pkt.Leaderboard == 6 || pkt.Leaderboard == 7 {
|
if pkt.Leaderboard == 2 || pkt.Leaderboard == 3 || pkt.Leaderboard == 6 || pkt.Leaderboard == 7 {
|
||||||
if guild.ID == 0 || IsGuildApplicant(s, s.charID) {
|
if guild == nil {
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 11))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 11))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ func encodeServerInfo(config *_config.Config, s *Server, local bool) []byte {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
bf.WriteUint32(uint32(channelserver.TimeAdjusted().Unix()))
|
bf.WriteUint32(uint32(channelserver.TimeAdjusted().Unix()))
|
||||||
bf.WriteUint32(uint32(s.erupeConfig.GameplayOptions.ClanMemberLimits[len(s.erupeConfig.GameplayOptions.ClanMemberLimits)-1][1]))
|
bf.WriteUint32(60)
|
||||||
return bf.Data()
|
return bf.Data()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -135,203 +135,7 @@ func (s *Session) makeSignResponse(uid uint32) []byte {
|
|||||||
|
|
||||||
bf.WriteUint32(s.server.getLastCID(uid))
|
bf.WriteUint32(s.server.getLastCID(uid))
|
||||||
bf.WriteUint32(s.server.getUserRights(uid))
|
bf.WriteUint32(s.server.getUserRights(uid))
|
||||||
|
ps.Uint16(bf, "", false) // filters
|
||||||
namNGWords := []string{}
|
|
||||||
msgNGWords := []string{}
|
|
||||||
|
|
||||||
filters := byteframe.NewByteFrame()
|
|
||||||
filters.SetLE()
|
|
||||||
filters.WriteNullTerminatedBytes([]byte("smc"))
|
|
||||||
smc := byteframe.NewByteFrame()
|
|
||||||
smc.SetLE()
|
|
||||||
smcData := []struct {
|
|
||||||
charGroup [][]rune
|
|
||||||
}{
|
|
||||||
{[][]rune{{'='}, {'='}}},
|
|
||||||
{[][]rune{{')'}, {')'}}},
|
|
||||||
{[][]rune{{'('}, {'('}}},
|
|
||||||
{[][]rune{{'!'}, {'!'}}},
|
|
||||||
{[][]rune{{'/'}, {'/'}}},
|
|
||||||
{[][]rune{{'+'}, {'+'}}},
|
|
||||||
{[][]rune{{'&'}, {'&'}}},
|
|
||||||
{[][]rune{{'ぼ'}, {'ボ'}, {'ホ', '゙'}, {'ほ', '゙'}, {'ホ', '゙'}, {'ほ', '゛'}, {'ホ', '゛'}, {'ホ', '゛'}}},
|
|
||||||
{[][]rune{{'べ'}, {'ベ'}, {'ヘ', '゙'}, {'へ', '゙'}, {'ヘ', '゙'}, {'へ', '゛'}, {'ヘ', '゛'}, {'ヘ', '゛'}}},
|
|
||||||
{[][]rune{{'で'}, {'デ'}, {'テ', '゙'}, {'て', '゙'}, {'テ', '゙'}, {'て', '゛'}, {'テ', '゛'}, {'テ', '゛'}, {'〒', '゛'}, {'〒', '゙'}, {'乙', '゙'}, {'乙', '゛'}}},
|
|
||||||
{[][]rune{{'び'}, {'ビ'}, {'ヒ', '゙'}, {'ひ', '゙'}, {'ヒ', '゙'}, {'ひ', '゛'}, {'ヒ', '゛'}, {'ヒ', '゛'}}},
|
|
||||||
{[][]rune{{'ど'}, {'ド'}, {'ト', '゙'}, {'と', '゙'}, {'ト', '゙'}, {'と', '゛'}, {'ト', '゛'}, {'ト', '゛'}, {'┣', '゙'}, {'┣', '゛'}, {'├', '゙'}, {'├', '゛'}}},
|
|
||||||
{[][]rune{{'ば'}, {'バ'}, {'ハ', '゙'}, {'は', '゙'}, {'ハ', '゙'}, {'八', '゙'}, {'は', '゛'}, {'ハ', '゛'}, {'ハ', '゛'}, {'八', '゛'}}},
|
|
||||||
{[][]rune{{'つ', '゙'}, {'ヅ'}, {'ツ', '゙'}, {'つ', '゛'}, {'ツ', '゛'}, {'ツ', '゙'}, {'ツ', '゛'}, {'づ'}, {'っ', '゙'}, {'ッ', '゙'}, {'ッ', '゙'}, {'っ', '゛'}, {'ッ', '゛'}, {'ッ', '゛'}}},
|
|
||||||
{[][]rune{{'ぶ'}, {'ブ'}, {'フ', '゙'}, {'ヴ'}, {'ウ', '゙'}, {'う', '゛'}, {'う', '゙'}, {'ウ', '゙'}, {'ゥ', '゙'}, {'ぅ', '゙'}, {'ふ', '゙'}, {'フ', '゙'}, {'フ', '゛'}}},
|
|
||||||
{[][]rune{{'ぢ'}, {'ヂ'}, {'チ', '゙'}, {'ち', '゙'}, {'チ', '゙'}, {'ち', '゛'}, {'チ', '゛'}, {'チ', '゛'}, {'千', '゛'}, {'千', '゙'}}},
|
|
||||||
{[][]rune{{'だ'}, {'ダ'}, {'タ', '゙'}, {'た', '゙'}, {'タ', '゙'}, {'夕', '゙'}, {'た', '゛'}, {'タ', '゛'}, {'タ', '゛'}, {'夕', '゛'}}},
|
|
||||||
{[][]rune{{'ぞ'}, {'ゾ'}, {'ソ', '゙'}, {'そ', '゙'}, {'ソ', '゙'}, {'そ', '゛'}, {'ソ', '゛'}, {'ソ', '゛'}, {'ン', '゙'}, {'ン', '゛'}, {'ン', '゛'}, {'ン', '゙'}, {'リ', '゙'}, {'リ', '゙'}, {'リ', '゛'}, {'リ', '゛'}}},
|
|
||||||
{[][]rune{{'ぜ'}, {'セ', '゙'}, {'せ', '゙'}, {'セ', '゙'}, {'せ', '゛'}, {'セ', '゛'}, {'セ', '゛'}, {'ゼ'}}},
|
|
||||||
{[][]rune{{'ず'}, {'ズ'}, {'ス', '゙'}, {'す', '゙'}, {'ス', '゙'}, {'す', '゛'}, {'ス', '゛'}, {'ス', '゛'}}},
|
|
||||||
{[][]rune{{'じ'}, {'ジ'}, {'シ', '゙'}, {'し', '゙'}, {'シ', '゙'}, {'し', '゛'}, {'シ', '゛'}, {'シ', '゛'}}},
|
|
||||||
{[][]rune{{'ざ'}, {'ザ'}, {'サ', '゙'}, {'さ', '゙'}, {'サ', '゙'}, {'さ', '゛'}, {'サ', '゛'}, {'サ', '゛'}}},
|
|
||||||
{[][]rune{{'ご'}, {'ゴ'}, {'コ', '゙'}, {'こ', '゙'}, {'コ', '゙'}, {'こ', '゛'}, {'コ', '゛'}, {'コ', '゛'}}},
|
|
||||||
{[][]rune{{'げ'}, {'ゲ'}, {'ケ', '゙'}, {'け', '゙'}, {'ケ', '゙'}, {'け', '゛'}, {'ケ', '゛'}, {'ケ', '゛'}, {'ヶ', '゙'}, {'ヶ', '゛'}}},
|
|
||||||
{[][]rune{{'ぐ'}, {'グ'}, {'ク', '゙'}, {'く', '゙'}, {'ク', '゙'}, {'く', '゛'}, {'ク', '゛'}, {'ク', '゛'}}},
|
|
||||||
{[][]rune{{'ぎ'}, {'ギ'}, {'キ', '゙'}, {'き', '゙'}, {'キ', '゙'}, {'き', '゛'}, {'キ', '゛'}, {'キ', '゛'}}},
|
|
||||||
{[][]rune{{'が'}, {'ガ'}, {'カ', '゙'}, {'ヵ', '゙'}, {'カ', '゙'}, {'か', '゙'}, {'力', '゙'}, {'ヵ', '゛'}, {'カ', '゛'}, {'か', '゛'}, {'力', '゛'}, {'カ', '゛'}}},
|
|
||||||
{[][]rune{{'を'}, {'ヲ'}, {'ヲ'}}},
|
|
||||||
{[][]rune{{'わ'}, {'ワ'}, {'ワ'}, {'ヮ'}}},
|
|
||||||
{[][]rune{{'ろ'}, {'ロ'}, {'ロ'}, {'□'}, {'口'}}},
|
|
||||||
{[][]rune{{'れ'}, {'レ'}, {'レ'}}},
|
|
||||||
{[][]rune{{'る'}, {'ル'}, {'ル'}}},
|
|
||||||
{[][]rune{{'り'}, {'リ'}, {'リ'}}},
|
|
||||||
{[][]rune{{'ら'}, {'ラ'}, {'ラ'}}},
|
|
||||||
{[][]rune{{'よ'}, {'ヨ'}, {'ヨ'}, {'ョ'}, {'ょ'}, {'ョ'}}},
|
|
||||||
{[][]rune{{'ゆ'}, {'ユ'}, {'ユ'}, {'ュ'}, {'ゅ'}, {'ュ'}}},
|
|
||||||
{[][]rune{{'や'}, {'ヤ'}, {'ヤ'}, {'ャ'}, {'ゃ'}, {'ャ'}}},
|
|
||||||
{[][]rune{{'も'}, {'モ'}, {'モ'}}},
|
|
||||||
{[][]rune{{'め'}, {'メ'}, {'メ'}, {'M', 'E'}}},
|
|
||||||
{[][]rune{{'む'}, {'ム'}, {'ム'}}},
|
|
||||||
{[][]rune{{'み'}, {'ミ'}, {'ミ'}}},
|
|
||||||
{[][]rune{{'ま'}, {'マ'}, {'マ'}}},
|
|
||||||
{[][]rune{{'ほ'}, {'ホ'}, {'ホ'}}},
|
|
||||||
{[][]rune{{'へ'}, {'ヘ'}, {'ヘ'}}},
|
|
||||||
{[][]rune{{'ふ'}, {'フ'}, {'フ'}}},
|
|
||||||
{[][]rune{{'ひ'}, {'ヒ'}, {'ヒ'}}},
|
|
||||||
{[][]rune{{'は'}, {'ハ'}, {'ハ'}, {'八'}}},
|
|
||||||
{[][]rune{{'の'}, {'ノ'}, {'ノ'}}},
|
|
||||||
{[][]rune{{'ね'}, {'ネ'}, {'ネ'}}},
|
|
||||||
{[][]rune{{'ぬ'}, {'ヌ'}, {'ヌ'}}},
|
|
||||||
{[][]rune{{'に'}, {'ニ'}, {'ニ'}, {'二'}}},
|
|
||||||
{[][]rune{{'な'}, {'ナ'}, {'ナ'}}},
|
|
||||||
{[][]rune{{'と'}, {'ト'}, {'ト'}, {'┣'}, {'├'}}},
|
|
||||||
{[][]rune{{'て'}, {'テ'}, {'テ'}, {'〒'}, {'乙'}}},
|
|
||||||
{[][]rune{{'つ'}, {'ツ'}, {'ツ'}, {'っ'}, {'ッ'}, {'ッ'}}},
|
|
||||||
{[][]rune{{'ち'}, {'チ'}, {'チ'}, {'千'}}},
|
|
||||||
{[][]rune{{'た'}, {'タ'}, {'タ'}, {'夕'}}},
|
|
||||||
{[][]rune{{'そ'}, {'ソ'}, {'ソ'}}},
|
|
||||||
{[][]rune{{'せ'}, {'セ'}, {'セ'}}},
|
|
||||||
{[][]rune{{'す'}, {'ス'}, {'ス'}}},
|
|
||||||
{[][]rune{{'し'}, {'シ'}, {'シ'}}},
|
|
||||||
{[][]rune{{'さ'}, {'サ'}, {'サ'}}},
|
|
||||||
{[][]rune{{'こ'}, {'コ'}, {'コ'}}},
|
|
||||||
{[][]rune{{'け'}, {'ケ'}, {'ケ'}, {'ヶ'}}},
|
|
||||||
{[][]rune{{'く'}, {'ク'}, {'ク'}}},
|
|
||||||
{[][]rune{{'き'}, {'キ'}, {'キ'}}},
|
|
||||||
{[][]rune{{'か'}, {'カ'}, {'カ'}, {'ヵ'}, {'力'}}},
|
|
||||||
{[][]rune{{'お'}, {'オ'}, {'オ'}, {'ォ'}, {'ぉ'}, {'ォ'}}},
|
|
||||||
{[][]rune{{'え'}, {'エ'}, {'エ'}, {'ェ'}, {'ぇ'}, {'ェ'}, {'工'}}},
|
|
||||||
{[][]rune{{'う'}, {'ウ'}, {'ウ'}, {'ゥ'}, {'ぅ'}, {'ゥ'}}},
|
|
||||||
{[][]rune{{'い'}, {'イ'}, {'イ'}, {'ィ'}, {'ぃ'}, {'ィ'}}},
|
|
||||||
{[][]rune{{'あ'}, {'ア'}, {'ァ'}, {'ア'}, {'ぁ'}, {'ァ'}}},
|
|
||||||
{[][]rune{{'ー'}, {'―'}, {'‐'}, {'-'}, {'-'}, {'ー'}, {'一'}}},
|
|
||||||
{[][]rune{{'9'}, {'9'}}},
|
|
||||||
{[][]rune{{'8'}, {'8'}}},
|
|
||||||
{[][]rune{{'7'}, {'7'}}},
|
|
||||||
{[][]rune{{'6'}, {'6'}}},
|
|
||||||
{[][]rune{{'5'}, {'5'}}},
|
|
||||||
{[][]rune{{'4'}, {'4'}}},
|
|
||||||
{[][]rune{{'3'}, {'3'}}},
|
|
||||||
{[][]rune{{'2'}, {'2'}}},
|
|
||||||
{[][]rune{{'1'}, {'1'}}},
|
|
||||||
{[][]rune{{'ぽ'}, {'ポ'}, {'ホ', '゚'}, {'ほ', '゚'}, {'ホ', '゚'}, {'ホ', '°'}, {'ほ', '°'}, {'ホ', '°'}}},
|
|
||||||
{[][]rune{{'ぺ'}, {'ペ'}, {'ヘ', '゚'}, {'へ', '゚'}, {'ヘ', '゚'}, {'ヘ', '°'}, {'へ', '°'}, {'ヘ', '°'}}},
|
|
||||||
{[][]rune{{'ぷ'}, {'プ'}, {'フ', '゚'}, {'ふ', '゚'}, {'フ', '゚'}, {'フ', '°'}, {'ふ', '°'}, {'フ', '°'}}},
|
|
||||||
{[][]rune{{'ぴ'}, {'ピ'}, {'ヒ', '゚'}, {'ひ', '゚'}, {'ヒ', '゚'}, {'ヒ', '°'}, {'ひ', '°'}, {'ヒ', '°'}}},
|
|
||||||
{[][]rune{{'ぱ'}, {'パ'}, {'ハ', '゚'}, {'は', '゚'}, {'ハ', '゚'}, {'ハ', '°'}, {'は', '°'}, {'ハ', '°'}, {'八', '゚'}, {'八', '゜'}}},
|
|
||||||
{[][]rune{{'z'}, {'z'}, {'Z'}, {'Z'}, {'Ζ'}}},
|
|
||||||
{[][]rune{{'y'}, {'y'}, {'Y'}, {'Y'}, {'Υ'}, {'У'}, {'у'}}},
|
|
||||||
{[][]rune{{'x'}, {'x'}, {'X'}, {'X'}, {'Χ'}, {'χ'}, {'Х'}, {'×'}, {'х'}}},
|
|
||||||
{[][]rune{{'w'}, {'w'}, {'W'}, {'W'}, {'ω'}, {'Ш'}, {'ш'}, {'щ'}}},
|
|
||||||
{[][]rune{{'v'}, {'v'}, {'V'}, {'V'}, {'ν'}, {'υ'}}},
|
|
||||||
{[][]rune{{'u'}, {'u'}, {'U'}, {'U'}, {'μ'}, {'∪'}}},
|
|
||||||
{[][]rune{{'t'}, {'t'}, {'T'}, {'T'}, {'Τ'}, {'τ'}, {'Т'}, {'т'}}},
|
|
||||||
{[][]rune{{'s'}, {'s'}, {'S'}, {'S'}, {'∫'}, {'$'}, {'$'}}},
|
|
||||||
{[][]rune{{'r'}, {'r'}, {'R'}, {'R'}, {'Я'}, {'я'}}},
|
|
||||||
{[][]rune{{'q'}, {'q'}, {'Q'}, {'Q'}}},
|
|
||||||
{[][]rune{{'p'}, {'p'}, {'P'}, {'P'}, {'Ρ'}, {'ρ'}, {'Р'}, {'р'}}},
|
|
||||||
{[][]rune{{'o'}, {'o'}, {'O'}, {'O'}, {'○'}, {'Ο'}, {'ο'}, {'О'}, {'о'}, {'◯'}, {'〇'}, {'0'}, {'0'}}},
|
|
||||||
{[][]rune{{'n'}, {'n'}, {'N'}, {'N'}, {'Ν'}, {'η'}, {'ン'}, {'ん'}, {'ン'}}},
|
|
||||||
{[][]rune{{'m'}, {'m'}, {'M'}, {'M'}, {'Μ'}, {'М'}, {'м'}}},
|
|
||||||
{[][]rune{{'l'}, {'l'}, {'L'}, {'L'}, {'|'}}},
|
|
||||||
{[][]rune{{'k'}, {'k'}, {'K'}, {'K'}, {'Κ'}, {'κ'}, {'К'}, {'к'}}},
|
|
||||||
{[][]rune{{'j'}, {'j'}, {'J'}, {'J'}}},
|
|
||||||
{[][]rune{{'i'}, {'i'}, {'I'}, {'I'}, {'Ι'}}},
|
|
||||||
{[][]rune{{'h'}, {'h'}, {'H'}, {'H'}, {'Η'}, {'Н'}, {'н'}}},
|
|
||||||
{[][]rune{{'f'}, {'f'}, {'F'}, {'F'}}},
|
|
||||||
{[][]rune{{'g'}, {'g'}, {'G'}, {'G'}}},
|
|
||||||
{[][]rune{{'e'}, {'e'}, {'E'}, {'E'}, {'Ε'}, {'ε'}, {'Е'}, {'Ё'}, {'е'}, {'ё'}, {'∈'}}},
|
|
||||||
{[][]rune{{'d'}, {'d'}, {'D'}, {'D'}}},
|
|
||||||
{[][]rune{{'c'}, {'c'}, {'C'}, {'С'}, {'с'}, {'C'}, {'℃'}}},
|
|
||||||
{[][]rune{{'b'}, {'B'}, {'b'}, {'B'}, {'β'}, {'Β'}, {'В'}, {'в'}, {'ъ'}, {'ь'}, {'♭'}}},
|
|
||||||
{[][]rune{{'\''}, {'’'}}},
|
|
||||||
{[][]rune{{'a'}, {'A'}, {'a'}, {'A'}, {'α'}, {'@'}, {'@'}, {'а'}, {'Å'}, {'А'}, {'Α'}}},
|
|
||||||
{[][]rune{{'"'}, {'”'}}},
|
|
||||||
{[][]rune{{'%'}, {'%'}}},
|
|
||||||
}
|
|
||||||
for _, smcGroup := range smcData {
|
|
||||||
for _, smcPair := range smcGroup.charGroup {
|
|
||||||
smc.WriteUint16(stringsupport.ToNGWord(string(smcPair[0]))[0])
|
|
||||||
if len(smcPair) > 1 {
|
|
||||||
smc.WriteUint16(stringsupport.ToNGWord(string(smcPair[1]))[0])
|
|
||||||
} else {
|
|
||||||
smc.WriteUint16(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
smc.WriteUint32(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
filters.WriteUint32(uint32(len(smc.Data())))
|
|
||||||
filters.WriteBytes(smc.Data())
|
|
||||||
|
|
||||||
filters.WriteNullTerminatedBytes([]byte("nam"))
|
|
||||||
nam := byteframe.NewByteFrame()
|
|
||||||
nam.SetLE()
|
|
||||||
for _, word := range namNGWords {
|
|
||||||
parts := stringsupport.ToNGWord(word)
|
|
||||||
nam.WriteUint32(uint32(len(parts)))
|
|
||||||
for _, part := range parts {
|
|
||||||
nam.WriteUint16(part)
|
|
||||||
var i int16
|
|
||||||
j := int16(-1)
|
|
||||||
for _, smcGroup := range smcData {
|
|
||||||
if rune(part) == rune(stringsupport.ToNGWord(string(smcGroup.charGroup[0][0]))[0]) {
|
|
||||||
j = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
i += int16(len(smcGroup.charGroup) + 1)
|
|
||||||
}
|
|
||||||
nam.WriteInt16(j)
|
|
||||||
}
|
|
||||||
nam.WriteUint16(0)
|
|
||||||
nam.WriteInt16(-1)
|
|
||||||
}
|
|
||||||
filters.WriteUint32(uint32(len(nam.Data())))
|
|
||||||
filters.WriteBytes(nam.Data())
|
|
||||||
|
|
||||||
filters.WriteNullTerminatedBytes([]byte("msg"))
|
|
||||||
msg := byteframe.NewByteFrame()
|
|
||||||
msg.SetLE()
|
|
||||||
for _, word := range msgNGWords {
|
|
||||||
parts := stringsupport.ToNGWord(word)
|
|
||||||
msg.WriteUint32(uint32(len(parts)))
|
|
||||||
for _, part := range parts {
|
|
||||||
msg.WriteUint16(part)
|
|
||||||
var i int16
|
|
||||||
j := int16(-1)
|
|
||||||
for _, smcGroup := range smcData {
|
|
||||||
if rune(part) == rune(stringsupport.ToNGWord(string(smcGroup.charGroup[0][0]))[0]) {
|
|
||||||
j = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
i += int16(len(smcGroup.charGroup) + 1)
|
|
||||||
}
|
|
||||||
msg.WriteInt16(j)
|
|
||||||
}
|
|
||||||
msg.WriteUint16(0)
|
|
||||||
msg.WriteInt16(-1)
|
|
||||||
}
|
|
||||||
filters.WriteUint32(uint32(len(msg.Data())))
|
|
||||||
filters.WriteBytes(msg.Data())
|
|
||||||
|
|
||||||
bf.WriteUint16(uint16(len(filters.Data())))
|
|
||||||
bf.WriteBytes(filters.Data())
|
|
||||||
|
|
||||||
if s.client == VITA || s.client == PS3 || s.client == PS4 {
|
if s.client == VITA || s.client == PS3 || s.client == PS4 {
|
||||||
var psnUser string
|
var psnUser string
|
||||||
s.server.db.QueryRow("SELECT psn_id FROM users WHERE id = $1", uid).Scan(&psnUser)
|
s.server.db.QueryRow("SELECT psn_id FROM users WHERE id = $1", uid).Scan(&psnUser)
|
||||||
|
|||||||
Reference in New Issue
Block a user