diff --git a/patch-schema/persistent-house.sql b/patch-schema/persistent-house.sql new file mode 100644 index 000000000..ee26333ee --- /dev/null +++ b/patch-schema/persistent-house.sql @@ -0,0 +1,19 @@ +BEGIN; + +CREATE TABLE IF NOT EXISTS public.user_binary +( + id serial NOT NULL PRIMARY KEY, + type2 bytea, + type3 bytea, + house_tier bytea, + house_state int, + house_password text, + house_data bytea, + house_furniture bytea, + bookshelf bytea, + gallery bytea, + tore bytea, + garden bytea +); + +END; \ No newline at end of file diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index 825924508..13459bda9 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -94,6 +94,9 @@ func (save *CharacterSaveData) Save(s *Session) { if err != nil { s.logger.Error("Failed to update savedata", zap.Error(err), zap.Uint32("charID", save.CharID)) } + + s.server.db.Exec(`UPDATE user_binary SET house_tier=$1, house_data=$2, bookshelf=$3, gallery=$4, tore=$5, garden=$6 WHERE id=$7 + `, save.HouseTier, save.HouseData, save.BookshelfData, save.GalleryData, save.ToreData, save.GardenData, s.charID) } func (save *CharacterSaveData) Compress() error { diff --git a/server/channelserver/handlers_house.go b/server/channelserver/handlers_house.go index 280f27238..3198b4c88 100644 --- a/server/channelserver/handlers_house.go +++ b/server/channelserver/handlers_house.go @@ -38,24 +38,26 @@ FROM warehouse func handleMsgMhfUpdateInterior(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfUpdateInterior) - _, err := s.server.db.Exec("UPDATE characters SET house=$1 WHERE id=$2", pkt.InteriorData, s.charID) - if err != nil { - panic(err) - } + s.server.db.Exec(`UPDATE user_binary SET house_furniture=$1 WHERE id=$2`, pkt.InteriorData, s.charID) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } type HouseData struct { - CharID uint32 `db:"id"` - HRP uint16 `db:"hrp"` - GR uint16 `db:"gr"` - Name string `db:"name"` + CharID uint32 `db:"id"` + HRP uint16 `db:"hrp"` + GR uint16 `db:"gr"` + Name string `db:"name"` + HouseState uint8 `db:"house_state"` + HousePassword string `db:"house_password"` } func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateHouse) bf := byteframe.NewByteFrame() + bf.WriteUint16(0) var houses []HouseData + houseQuery := `SELECT c.id, hrp, gr, name, COALESCE(ub.house_state, 2) as house_state, COALESCE(ub.house_password, '') as house_password + FROM characters c LEFT JOIN user_binary ub ON ub.id = c.id WHERE c.id=$1` switch pkt.Method { case 1: var friendsList string @@ -63,17 +65,15 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { cids := stringsupport.CSVElems(friendsList) for _, cid := range cids { house := HouseData{} - row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", cid) + row := s.server.db.QueryRowx(houseQuery, cid) err := row.StructScan(&house) - if err != nil { - panic(err) - } else { + if err == nil { houses = append(houses, house) } } case 2: guild, err := GetGuildInfoByCharacterId(s, s.charID) - if err != nil { + if err != nil || guild == nil { break } guildMembers, err := GetGuildMembers(s, guild.ID, false) @@ -82,58 +82,48 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { } for _, member := range guildMembers { house := HouseData{} - row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", member.CharID) - err := row.StructScan(&house) - if err != nil { - panic(err) - } else { + row := s.server.db.QueryRowx(houseQuery, member.CharID) + err = row.StructScan(&house) + if err == nil { houses = append(houses, house) } } case 3: + houseQuery = `SELECT c.id, hrp, gr, name, COALESCE(ub.house_state, 2) as house_state, COALESCE(ub.house_password, '') as house_password + FROM characters c LEFT JOIN user_binary ub ON ub.id = c.id WHERE name ILIKE $1` house := HouseData{} - row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE name ILIKE $1", fmt.Sprintf(`%%%s%%`, pkt.Name)) - err := row.StructScan(&house) - if err != nil { - panic(err) - } else { - houses = append(houses, house) + rows, _ := s.server.db.Queryx(houseQuery, fmt.Sprintf(`%%%s%%`, pkt.Name)) + for rows.Next() { + err := rows.StructScan(&house) + if err == nil { + houses = append(houses, house) + } } case 4: house := HouseData{} - row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", pkt.CharID) + row := s.server.db.QueryRowx(houseQuery, pkt.CharID) err := row.StructScan(&house) - if err != nil { - panic(err) - } else { + if err == nil { houses = append(houses, house) } case 5: // Recent visitors break } - var exists int for _, house := range houses { - for _, session := range s.server.sessions { - if session.charID == house.CharID { - exists++ - bf.WriteUint32(house.CharID) - bf.WriteUint8(session.myseries.state) - if len(session.myseries.password) > 0 { - bf.WriteUint8(3) - } else { - bf.WriteUint8(0) - } - bf.WriteUint16(house.HRP) - bf.WriteUint16(house.GR) - ps.Uint8(bf, house.Name, true) - break - } + bf.WriteUint32(house.CharID) + bf.WriteUint8(house.HouseState) + if len(house.HousePassword) > 0 { + bf.WriteUint8(3) + } else { + bf.WriteUint8(0) } + bf.WriteUint16(house.HRP) + bf.WriteUint16(house.GR) + ps.Uint8(bf, house.Name, true) } - resp := byteframe.NewByteFrame() - resp.WriteUint16(uint16(exists)) - resp.WriteBytes(bf.Data()) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + bf.Seek(0, 0) + bf.WriteUint16(uint16(len(houses))) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) { @@ -143,8 +133,7 @@ func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) { // 03 = open friends // 04 = open guild // 05 = open friends+guild - s.myseries.state = pkt.State - s.myseries.password = pkt.Password + s.server.db.Exec(`UPDATE user_binary SET house_state=$1, house_password=$2 WHERE id=$3`, pkt.State, pkt.Password, s.charID) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } @@ -152,63 +141,41 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfLoadHouse) bf := byteframe.NewByteFrame() if pkt.Destination != 9 && len(pkt.Password) > 0 && pkt.CheckPass { - for _, session := range s.server.sessions { - if session.charID == pkt.CharID && pkt.Password != session.myseries.password { - doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) - return - } + var password string + s.server.db.Select(&password, `SELECT house_password FROM user_binary WHERE id=$1`, pkt.CharID) + if pkt.Password != password { + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + return } } - var furniture []byte - err := s.server.db.QueryRow("SELECT house FROM characters WHERE id=$1", pkt.CharID).Scan(&furniture) - if err != nil { - panic(err) - } - if furniture == nil { - furniture = make([]byte, 20) + var houseTier, houseData, houseFurniture, bookshelf, gallery, tore, garden []byte + s.server.db.QueryRow(`SELECT house_tier, house_data, house_furniture, bookshelf, gallery, tore, garden FROM user_binary WHERE id=$1 + `, pkt.CharID).Scan(&houseTier, &houseData, &houseFurniture, &bookshelf, &gallery, &tore, &garden) + if houseFurniture == nil { + houseFurniture = make([]byte, 20) } switch pkt.Destination { case 3: // Others house - for _, session := range s.server.sessions { - if session.charID == pkt.CharID { - bf.WriteBytes(session.myseries.houseTier) - bf.WriteBytes(session.myseries.houseData) - bf.WriteBytes(make([]byte, 19)) // Padding? - bf.WriteBytes(furniture) - } - } + bf.WriteBytes(houseTier) + bf.WriteBytes(houseData) + bf.WriteBytes(make([]byte, 19)) // Padding? + bf.WriteBytes(houseFurniture) case 4: // Bookshelf - for _, session := range s.server.sessions { - if session.charID == pkt.CharID { - bf.WriteBytes(session.myseries.bookshelfData) - } - } + bf.WriteBytes(bookshelf) case 5: // Gallery - for _, session := range s.server.sessions { - if session.charID == pkt.CharID { - bf.WriteBytes(session.myseries.galleryData) - } - } + bf.WriteBytes(gallery) case 8: // Tore - for _, session := range s.server.sessions { - if session.charID == pkt.CharID { - bf.WriteBytes(session.myseries.toreData) - } - } + bf.WriteBytes(tore) case 9: // Own house - bf.WriteBytes(furniture) + bf.WriteBytes(houseFurniture) case 10: // Garden - for _, session := range s.server.sessions { - if session.charID == pkt.CharID { - bf.WriteBytes(session.myseries.gardenData) - c, d := getGookData(s, pkt.CharID) - bf.WriteUint16(c) - bf.WriteUint16(0) - bf.WriteBytes(d) - } - } + bf.WriteBytes(garden) + c, d := getGookData(s, pkt.CharID) + bf.WriteUint16(c) + bf.WriteUint16(0) + bf.WriteBytes(d) } if len(bf.Data()) == 0 { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) diff --git a/server/channelserver/handlers_users.go b/server/channelserver/handlers_users.go index 3bebcc97a..c360b82a6 100644 --- a/server/channelserver/handlers_users.go +++ b/server/channelserver/handlers_users.go @@ -17,12 +17,12 @@ func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) { s.server.userBinaryPartsLock.Unlock() var exists []byte - err := s.server.db.QueryRow("SELECT type2 FROM user_binaries WHERE id=$1", s.charID).Scan(&exists) + err := s.server.db.QueryRow("SELECT type2 FROM user_binary WHERE id=$1", s.charID).Scan(&exists) if err != nil { - s.server.db.Exec("INSERT INTO user_binaries (id) VALUES ($1)", s.charID) + s.server.db.Exec("INSERT INTO user_binary (id) VALUES ($1)", s.charID) } - s.server.db.Exec(fmt.Sprintf("UPDATE user_binaries SET type%d=$1 WHERE id=$2", pkt.BinaryType), pkt.RawDataPayload, s.charID) + s.server.db.Exec(fmt.Sprintf("UPDATE user_binary SET type%d=$1 WHERE id=$2", pkt.BinaryType), pkt.RawDataPayload, s.charID) msg := &mhfpacket.MsgSysNotifyUserBinary{ CharID: s.charID, @@ -42,7 +42,7 @@ func handleMsgSysGetUserBinary(s *Session, p mhfpacket.MHFPacket) { // If we can't get the real data, try to get it from the database. if !ok { - err := s.server.db.QueryRow(fmt.Sprintf("SELECT type%d FROM user_binaries WHERE id=$1", pkt.BinaryType), pkt.CharID).Scan(&data) + err := s.server.db.QueryRow(fmt.Sprintf("SELECT type%d FROM user_binary WHERE id=$1", pkt.BinaryType), pkt.CharID).Scan(&data) if err != nil { doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) } else {