mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-02-04 17:22:16 +01:00
partially implement friend list functionality
This commit is contained in:
@@ -165,7 +165,7 @@ func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, err = s.server.db.Exec("UPDATE sign_sessions SET server_id=$1 WHERE token=$2", s.server.ID, s.token)
|
||||
_, err = s.server.db.Exec("UPDATE sign_sessions SET server_id=$1, char_id=$2 WHERE token=$3", s.server.ID, s.charID, s.token)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -198,7 +198,7 @@ func logoutPlayer(s *Session) {
|
||||
delete(s.server.sessions, s.rawConn)
|
||||
s.rawConn.Close()
|
||||
|
||||
_, err := s.server.db.Exec("UPDATE sign_sessions SET server_id=NULL WHERE token=$1", s.token)
|
||||
_, err := s.server.db.Exec("UPDATE sign_sessions SET server_id=NULL, char_id=NULL WHERE token=$1", s.token)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ func (s *Server) handleEntranceServerConnection(conn net.Conn) {
|
||||
|
||||
data := makeSv2Resp(s.erupeConfig.Entrance.Entries, s)
|
||||
if len(pkt) > 5 {
|
||||
data = append(data, makeUsrResp(pkt)...)
|
||||
data = append(data, makeUsrResp(pkt, s)...)
|
||||
}
|
||||
cc.SendPacket(data)
|
||||
// Close because we only need to send the response once.
|
||||
|
||||
@@ -88,24 +88,23 @@ func makeSv2Resp(servers []config.EntranceServerInfo, s *Server) []byte {
|
||||
return bf.Data()
|
||||
}
|
||||
|
||||
func makeUsrResp(pkt []byte) []byte {
|
||||
// TODO(Andoryuuta): Figure out what this user data is.
|
||||
// Is it for the friends list at the world selection screen?
|
||||
// If so, how does it work without the entrance server connection being authenticated?
|
||||
|
||||
// uint16 for number of requested ids
|
||||
// uint32 for each id
|
||||
// response seems to be server number starting from 10 10 00 00 for server 1 channel 1?
|
||||
func makeUsrResp(pkt []byte, s *Server) []byte {
|
||||
bf := byteframe.NewByteFrameFromBytes(pkt)
|
||||
_ = bf.ReadUint32() // ALL+
|
||||
_ = bf.ReadUint8() // 0x00
|
||||
|
||||
userEntries := bf.ReadUint16()
|
||||
// actual process will be reading all ids and returning real server, just returning all in server 1 for now
|
||||
bf = byteframe.NewByteFrame()
|
||||
resp := byteframe.NewByteFrame()
|
||||
for i := 0; i < int(userEntries); i++ {
|
||||
bf.WriteBytes([]byte{0x10, 0x10, 0x00, 0x00})
|
||||
cid := bf.ReadUint32()
|
||||
var sid uint16
|
||||
err := s.db.QueryRow("SELECT(SELECT server_id FROM sign_sessions WHERE char_id=$1) AS _", cid).Scan(&sid)
|
||||
if err != nil {
|
||||
resp.WriteBytes(make([]byte, 4))
|
||||
continue
|
||||
} else {
|
||||
resp.WriteUint16(sid)
|
||||
resp.WriteUint16(0)
|
||||
}
|
||||
}
|
||||
return makeHeader(bf.Data(), "USR", userEntries, 0x00)
|
||||
|
||||
return makeHeader(resp.Data(), "USR", userEntries, 0x00)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package signserver
|
||||
|
||||
import (
|
||||
"time"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
@@ -87,13 +88,60 @@ 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", 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 ORDER BY last_login DESC", uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return characters, nil
|
||||
}
|
||||
|
||||
type members struct {
|
||||
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="
|
||||
}
|
||||
}
|
||||
err = s.db.Select(&friends, friendQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return friends, nil
|
||||
}
|
||||
|
||||
func (s *Server) getGuildmatesForCharacter(cid uint32) ([]members, error) {
|
||||
guildmates := []members{}
|
||||
var inGuild int
|
||||
_ = s.db.QueryRow("SELECT count(*) FROM guild_characters WHERE character_id=$1", cid).Scan(&inGuild)
|
||||
if inGuild > 0 {
|
||||
var guildID int
|
||||
err := s.db.QueryRow("SELECT guild_id FROM guild_characters WHERE character_id=$1", cid).Scan(&guildID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = s.db.Select(&guildmates, "SELECT character_id AS id, c.name FROM guild_characters gc JOIN characters c ON c.id = gc.character_id WHERE guild_id=$1 AND character_id!=$2", guildID, cid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return guildmates, nil
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) deleteCharacter(cid int, token string) error {
|
||||
var verify int
|
||||
err := s.db.QueryRow("SELECT count(*) FROM sign_sessions WHERE token = $1", token).Scan(&verify)
|
||||
|
||||
@@ -46,10 +46,14 @@ func (s *Session) makeSignInResp(uid int) []byte {
|
||||
bf.WriteUint8(uint8(len(chars))) // character count
|
||||
bf.WriteUint32(0xFFFFFFFF) // login_token_number
|
||||
bf.WriteBytes([]byte(token)) // login_token
|
||||
bf.WriteUint32(uint32(time.Now().Unix())) // unk timestamp
|
||||
bf.WriteUint32(uint32(time.Now().Unix())) // current time
|
||||
ps.Uint8(bf, fmt.Sprintf("%s:%d", s.server.erupeConfig.HostIP, s.server.erupeConfig.Entrance.Port), false)
|
||||
|
||||
lastPlayed := uint32(0)
|
||||
for _, char := range chars {
|
||||
if lastPlayed == 0 {
|
||||
lastPlayed = char.ID
|
||||
}
|
||||
bf.WriteUint32(char.ID)
|
||||
|
||||
// Exp, HR[x] is split by 0, 1, 30, 50, 99, 299, 998, 999
|
||||
@@ -71,18 +75,39 @@ func (s *Session) makeSignInResp(uid int) []byte {
|
||||
bf.WriteUint16(0) // Unk
|
||||
}
|
||||
|
||||
bf.WriteUint8(0) // friends_list_count
|
||||
bf.WriteUint8(0) // guild_members_count
|
||||
friends, err := s.server.getFriendsForCharacter(lastPlayed)
|
||||
if err != nil || friends == nil {
|
||||
bf.WriteUint8(0)
|
||||
} else {
|
||||
bf.WriteUint8(uint8(len(friends)))
|
||||
for _, friend := range friends {
|
||||
bf.WriteUint32(lastPlayed)
|
||||
bf.WriteUint32(friend.ID)
|
||||
ps.Uint8(bf, friend.Name, true)
|
||||
}
|
||||
}
|
||||
|
||||
guildmates, err := s.server.getGuildmatesForCharacter(lastPlayed)
|
||||
if err != nil || guildmates == nil {
|
||||
bf.WriteUint8(0)
|
||||
} else {
|
||||
for _, guildmate := range guildmates {
|
||||
bf.WriteUint32(lastPlayed)
|
||||
bf.WriteUint32(guildmate.ID)
|
||||
ps.Uint8(bf, guildmate.Name, true)
|
||||
}
|
||||
}
|
||||
|
||||
bf.WriteUint8(0) // notice_count
|
||||
|
||||
// noticeText := "<BODY><CENTER><SIZE_3><C_4>Welcome to Erupe SU9!<BR><BODY><LEFT><SIZE_2><C_5>Erupe is experimental software<C_7>, we are not liable for any<BR><BODY>issues caused by installing the software!<BR><BODY><BR><BODY><C_4>■Report bugs on Discord!<C_7><BR><BODY><BR><BODY><C_4>■Test everything!<C_7><BR><BODY><BR><BODY><C_4>■Don't talk to softlocking NPCs!<C_7><BR><BODY><BR><BODY><C_4>■Fork the code on GitHub!<C_7><BR><BODY><BR><BODY>Thank you to all of the contributors,<BR><BODY><BR><BODY>this wouldn't exist without you."
|
||||
// ps.Uint32(bf, noticeText, true)
|
||||
|
||||
bf.WriteUint32(0) // some_last_played_character_id
|
||||
bf.WriteUint32(14) // unk_flags
|
||||
ps.Uint16(bf, "", false) // filters
|
||||
bf.WriteUint32(lastPlayed) // last played character id
|
||||
bf.WriteUint32(14) // course bitfield
|
||||
ps.Uint16(bf, "", false) // filters
|
||||
bf.WriteUint32(0xCA104E20)
|
||||
ps.Uint16(bf, "", false) // encryption
|
||||
ps.Uint16(bf, "", false) // encryption
|
||||
bf.WriteUint8(0x00)
|
||||
bf.WriteUint32(0xCA110001)
|
||||
bf.WriteUint32(0x4E200000)
|
||||
|
||||
@@ -4,6 +4,7 @@ DROP TABLE IF EXISTS public.sign_sessions;
|
||||
CREATE TABLE IF NOT EXISTS public.sign_sessions
|
||||
(
|
||||
user_id int NOT NULL,
|
||||
char_id int,
|
||||
token varchar(16) NOT NULL,
|
||||
server_id integer
|
||||
);
|
||||
@@ -19,4 +20,7 @@ CREATE TABLE IF NOT EXISTS public.servers
|
||||
ALTER TABLE IF EXISTS public.characters
|
||||
ADD COLUMN deleted boolean NOT NULL DEFAULT false;
|
||||
|
||||
ALTER TABLE IF EXISTS public.characters
|
||||
ADD COLUMN friends text NOT NULL DEFAULT '';
|
||||
|
||||
END;
|
||||
|
||||
Reference in New Issue
Block a user