From cd26a96dfd409b7b33ecc54effb7e41fe18e1beb Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 17 Jul 2022 03:10:45 +1000 Subject: [PATCH] enumerate friends list across characters --- Erupe/common/stringsupport/string_convert.go | 31 ++++++++++++++ Erupe/network/mhfpacket/msg_mhf_opr_member.go | 19 +++++++-- .../server/channelserver/handlers_clients.go | 23 +++++++++- Erupe/server/signserver/dbutils.go | 42 +++++++++++-------- Erupe/server/signserver/dsgn_resp.go | 6 +-- 5 files changed, 95 insertions(+), 26 deletions(-) diff --git a/Erupe/common/stringsupport/string_convert.go b/Erupe/common/stringsupport/string_convert.go index 4764db8c8..bc0039ba6 100644 --- a/Erupe/common/stringsupport/string_convert.go +++ b/Erupe/common/stringsupport/string_convert.go @@ -1,6 +1,8 @@ package stringsupport import ( + "strings" + "strconv" "bytes" "io/ioutil" @@ -114,6 +116,35 @@ func PaddedString(x string, size uint, t bool) []byte { return out } +func CSVAdd(csv string, v int) string { + if len(csv) == 0 { + return strconv.Itoa(v) + } + return csv + "," + strconv.Itoa(v) +} + +func CSVRemove(csv string, v int) string { + s := strings.Split(csv, ",") + for i, e := range s { + if e == strconv.Itoa(v) { + s[i] = s[len(s) - 1] + s = s[:len(s) - 1] + } + } + return strings.Join(s, ",") +} + +func CSVContains(csv string, v int) bool { + s := strings.Split(csv, ",") + for i := 0; i < len(s); i++ { + j, _ := strconv.ParseInt(s[i], 10, 64) + if int(j) == v { + return true + } + } + return false +} + // ConvertUTF8ToShiftJIS converts a UTF8 string to a Shift-JIS []byte. func ConvertUTF8ToShiftJIS(text string) ([]byte, error) { r := bytes.NewBuffer([]byte(text)) diff --git a/Erupe/network/mhfpacket/msg_mhf_opr_member.go b/Erupe/network/mhfpacket/msg_mhf_opr_member.go index 5625b9536..32641cb39 100644 --- a/Erupe/network/mhfpacket/msg_mhf_opr_member.go +++ b/Erupe/network/mhfpacket/msg_mhf_opr_member.go @@ -1,7 +1,7 @@ package mhfpacket -import ( - "errors" +import ( + "errors" "erupe-ce/network/clientctx" "erupe-ce/network" @@ -9,7 +9,13 @@ import ( ) // MsgMhfOprMember represents the MSG_MHF_OPR_MEMBER -type MsgMhfOprMember struct{} +type MsgMhfOprMember struct { + AckHandle uint32 + Blacklist bool + Operation bool + Unk uint16 + CharID uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfOprMember) Opcode() network.PacketID { @@ -18,7 +24,12 @@ func (m *MsgMhfOprMember) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfOprMember) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Blacklist = bf.ReadBool() + m.Operation = bf.ReadBool() + m.Unk = bf.ReadUint16() + m.CharID = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. diff --git a/Erupe/server/channelserver/handlers_clients.go b/Erupe/server/channelserver/handlers_clients.go index 7710343d8..241717498 100644 --- a/Erupe/server/channelserver/handlers_clients.go +++ b/Erupe/server/channelserver/handlers_clients.go @@ -1,6 +1,7 @@ package channelserver import ( + "erupe-ce/common/stringsupport" "erupe-ce/network/mhfpacket" "erupe-ce/common/byteframe" "go.uber.org/zap" @@ -60,8 +61,26 @@ func handleMsgMhfListMember(s *Session, p mhfpacket.MHFPacket) { } func handleMsgMhfOprMember(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgMhfListMember) - // TODO: add targetid(uint32) to charid(uint32)'s database under new field + pkt := p.(*mhfpacket.MsgMhfOprMember) + var csv string + if pkt.Blacklist { + if pkt.Operation { + // remove from blacklist + } else { + // add to blacklist + } + } else { // Friendlist + err := s.server.db.QueryRow("SELECT friends FROM characters WHERE id=$1", s.charID).Scan(&csv) + if err != nil { + panic(err) + } + if pkt.Operation { + csv = stringsupport.CSVRemove(csv, int(pkt.CharID)) + } else { + csv = stringsupport.CSVAdd(csv, int(pkt.CharID)) + } + _, _ = s.server.db.Exec("UPDATE characters SET friends=$1 WHERE id=$2", csv, s.charID) + } doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } diff --git a/Erupe/server/signserver/dbutils.go b/Erupe/server/signserver/dbutils.go index 3cadaefbc..88cf94a5b 100644 --- a/Erupe/server/signserver/dbutils.go +++ b/Erupe/server/signserver/dbutils.go @@ -88,7 +88,7 @@ type character struct { func (s *Server) getCharactersForUser(uid int) ([]character, error) { characters := []character{} - err := s.db.Select(&characters, "SELECT id, is_female, is_new_character, name, unk_desc_string, hrp, gr, weapon_type, last_login FROM characters WHERE user_id = $1 AND deleted = false ORDER BY last_login DESC", uid) + err := s.db.Select(&characters, "SELECT id, is_female, is_new_character, name, unk_desc_string, hrp, gr, weapon_type, last_login FROM characters WHERE user_id = $1 AND deleted = false", uid) if err != nil { return nil, err } @@ -96,28 +96,36 @@ func (s *Server) getCharactersForUser(uid int) ([]character, error) { } type members struct { + CID uint32 // Local character ID ID uint32 `db:"id"` Name string `db:"name"` } -func (s *Server) getFriendsForCharacter(cid uint32) ([]members, error) { - friends := []members{} - var friendsCSV string - err := s.db.QueryRow("SELECT friends FROM characters WHERE id=$1", cid).Scan(&friendsCSV) - friendsSlice := strings.Split(friendsCSV, ",") - if friendsSlice[0] == "" { - return nil, nil - } - friendQuery := "SELECT id, name FROM characters WHERE id=" - for i := 0; i < len(friendsSlice); i++ { - friendQuery += friendsSlice[i] - if i + 1 != len(friendsSlice) { - friendQuery += " OR id=" +func (s *Server) getFriendsForCharacters(chars []character) ([]members, error) { + friends := make([]members, 0) + for _, char := range chars { + friendsCSV := "" + err := s.db.QueryRow("SELECT friends FROM characters WHERE id=$1", char.ID).Scan(&friendsCSV) + friendsSlice := strings.Split(friendsCSV, ",") + friendQuery := "SELECT id, name FROM characters WHERE id=" + for i := 0; i < len(friendsSlice); i++ { + friendQuery += friendsSlice[i] + if i + 1 != len(friendsSlice) { + friendQuery += " OR id=" + } } + charFriends := []members{} + err = s.db.Select(&charFriends, friendQuery) + if err != nil { + continue + } + for i, _ := range charFriends { + charFriends[i].CID = char.ID + } + friends = append(friends, charFriends...) } - err = s.db.Select(&friends, friendQuery) - if err != nil { - return nil, err + if len(friends) > 255 { // Uint8 + friends = friends[:255] } return friends, nil } diff --git a/Erupe/server/signserver/dsgn_resp.go b/Erupe/server/signserver/dsgn_resp.go index 2b55b6fd4..cd6f957c9 100644 --- a/Erupe/server/signserver/dsgn_resp.go +++ b/Erupe/server/signserver/dsgn_resp.go @@ -75,13 +75,13 @@ func (s *Session) makeSignInResp(uid int) []byte { bf.WriteUint16(0) // Unk } - friends, err := s.server.getFriendsForCharacter(lastPlayed) - if err != nil || friends == nil { + friends, err := s.server.getFriendsForCharacters(chars) + if err != nil || len(friends) == 0 { bf.WriteUint8(0) } else { bf.WriteUint8(uint8(len(friends))) for _, friend := range friends { - bf.WriteUint32(lastPlayed) + bf.WriteUint32(friend.CID) bf.WriteUint32(friend.ID) ps.Uint8(bf, friend.Name, true) }