implement persistent house data

This commit is contained in:
wish
2022-09-04 15:53:24 +10:00
parent 6c9e39a5cd
commit 9259476316
4 changed files with 88 additions and 99 deletions

View File

@@ -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;

View File

@@ -94,6 +94,9 @@ func (save *CharacterSaveData) Save(s *Session) {
if err != nil { if err != nil {
s.logger.Error("Failed to update savedata", zap.Error(err), zap.Uint32("charID", save.CharID)) 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 { func (save *CharacterSaveData) Compress() error {

View File

@@ -38,24 +38,26 @@ FROM warehouse
func handleMsgMhfUpdateInterior(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateInterior(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateInterior) pkt := p.(*mhfpacket.MsgMhfUpdateInterior)
_, err := s.server.db.Exec("UPDATE characters SET house=$1 WHERE id=$2", pkt.InteriorData, s.charID) s.server.db.Exec(`UPDATE user_binary SET house_furniture=$1 WHERE id=$2`, pkt.InteriorData, s.charID)
if err != nil {
panic(err)
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
type HouseData struct { type HouseData struct {
CharID uint32 `db:"id"` CharID uint32 `db:"id"`
HRP uint16 `db:"hrp"` HRP uint16 `db:"hrp"`
GR uint16 `db:"gr"` GR uint16 `db:"gr"`
Name string `db:"name"` Name string `db:"name"`
HouseState uint8 `db:"house_state"`
HousePassword string `db:"house_password"`
} }
func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateHouse) pkt := p.(*mhfpacket.MsgMhfEnumerateHouse)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint16(0)
var houses []HouseData 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 { switch pkt.Method {
case 1: case 1:
var friendsList string var friendsList string
@@ -63,17 +65,15 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
cids := stringsupport.CSVElems(friendsList) cids := stringsupport.CSVElems(friendsList)
for _, cid := range cids { for _, cid := range cids {
house := HouseData{} 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) err := row.StructScan(&house)
if err != nil { if err == nil {
panic(err)
} else {
houses = append(houses, house) houses = append(houses, house)
} }
} }
case 2: case 2:
guild, err := GetGuildInfoByCharacterId(s, s.charID) guild, err := GetGuildInfoByCharacterId(s, s.charID)
if err != nil { if err != nil || guild == nil {
break break
} }
guildMembers, err := GetGuildMembers(s, guild.ID, false) guildMembers, err := GetGuildMembers(s, guild.ID, false)
@@ -82,58 +82,48 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
} }
for _, member := range guildMembers { for _, member := range guildMembers {
house := HouseData{} house := HouseData{}
row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", member.CharID) row := s.server.db.QueryRowx(houseQuery, member.CharID)
err := row.StructScan(&house) err = row.StructScan(&house)
if err != nil { if err == nil {
panic(err)
} else {
houses = append(houses, house) houses = append(houses, house)
} }
} }
case 3: 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{} house := HouseData{}
row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE name ILIKE $1", fmt.Sprintf(`%%%s%%`, pkt.Name)) rows, _ := s.server.db.Queryx(houseQuery, fmt.Sprintf(`%%%s%%`, pkt.Name))
err := row.StructScan(&house) for rows.Next() {
if err != nil { err := rows.StructScan(&house)
panic(err) if err == nil {
} else { houses = append(houses, house)
houses = append(houses, house) }
} }
case 4: case 4:
house := HouseData{} 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) err := row.StructScan(&house)
if err != nil { if err == nil {
panic(err)
} else {
houses = append(houses, house) houses = append(houses, house)
} }
case 5: // Recent visitors case 5: // Recent visitors
break break
} }
var exists int
for _, house := range houses { for _, house := range houses {
for _, session := range s.server.sessions { bf.WriteUint32(house.CharID)
if session.charID == house.CharID { bf.WriteUint8(house.HouseState)
exists++ if len(house.HousePassword) > 0 {
bf.WriteUint32(house.CharID) bf.WriteUint8(3)
bf.WriteUint8(session.myseries.state) } else {
if len(session.myseries.password) > 0 { bf.WriteUint8(0)
bf.WriteUint8(3)
} else {
bf.WriteUint8(0)
}
bf.WriteUint16(house.HRP)
bf.WriteUint16(house.GR)
ps.Uint8(bf, house.Name, true)
break
}
} }
bf.WriteUint16(house.HRP)
bf.WriteUint16(house.GR)
ps.Uint8(bf, house.Name, true)
} }
resp := byteframe.NewByteFrame() bf.Seek(0, 0)
resp.WriteUint16(uint16(exists)) bf.WriteUint16(uint16(len(houses)))
resp.WriteBytes(bf.Data()) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) {
@@ -143,8 +133,7 @@ func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) {
// 03 = open friends // 03 = open friends
// 04 = open guild // 04 = open guild
// 05 = open friends+guild // 05 = open friends+guild
s.myseries.state = pkt.State s.server.db.Exec(`UPDATE user_binary SET house_state=$1, house_password=$2 WHERE id=$3`, pkt.State, pkt.Password, s.charID)
s.myseries.password = pkt.Password
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
@@ -152,63 +141,41 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadHouse) pkt := p.(*mhfpacket.MsgMhfLoadHouse)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
if pkt.Destination != 9 && len(pkt.Password) > 0 && pkt.CheckPass { if pkt.Destination != 9 && len(pkt.Password) > 0 && pkt.CheckPass {
for _, session := range s.server.sessions { var password string
if session.charID == pkt.CharID && pkt.Password != session.myseries.password { s.server.db.Select(&password, `SELECT house_password FROM user_binary WHERE id=$1`, pkt.CharID)
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) if pkt.Password != password {
return doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
} return
} }
} }
var furniture []byte var houseTier, houseData, houseFurniture, bookshelf, gallery, tore, garden []byte
err := s.server.db.QueryRow("SELECT house FROM characters WHERE id=$1", pkt.CharID).Scan(&furniture) s.server.db.QueryRow(`SELECT house_tier, house_data, house_furniture, bookshelf, gallery, tore, garden FROM user_binary WHERE id=$1
if err != nil { `, pkt.CharID).Scan(&houseTier, &houseData, &houseFurniture, &bookshelf, &gallery, &tore, &garden)
panic(err) if houseFurniture == nil {
} houseFurniture = make([]byte, 20)
if furniture == nil {
furniture = make([]byte, 20)
} }
switch pkt.Destination { switch pkt.Destination {
case 3: // Others house case 3: // Others house
for _, session := range s.server.sessions { bf.WriteBytes(houseTier)
if session.charID == pkt.CharID { bf.WriteBytes(houseData)
bf.WriteBytes(session.myseries.houseTier) bf.WriteBytes(make([]byte, 19)) // Padding?
bf.WriteBytes(session.myseries.houseData) bf.WriteBytes(houseFurniture)
bf.WriteBytes(make([]byte, 19)) // Padding?
bf.WriteBytes(furniture)
}
}
case 4: // Bookshelf case 4: // Bookshelf
for _, session := range s.server.sessions { bf.WriteBytes(bookshelf)
if session.charID == pkt.CharID {
bf.WriteBytes(session.myseries.bookshelfData)
}
}
case 5: // Gallery case 5: // Gallery
for _, session := range s.server.sessions { bf.WriteBytes(gallery)
if session.charID == pkt.CharID {
bf.WriteBytes(session.myseries.galleryData)
}
}
case 8: // Tore case 8: // Tore
for _, session := range s.server.sessions { bf.WriteBytes(tore)
if session.charID == pkt.CharID {
bf.WriteBytes(session.myseries.toreData)
}
}
case 9: // Own house case 9: // Own house
bf.WriteBytes(furniture) bf.WriteBytes(houseFurniture)
case 10: // Garden case 10: // Garden
for _, session := range s.server.sessions { bf.WriteBytes(garden)
if session.charID == pkt.CharID { c, d := getGookData(s, pkt.CharID)
bf.WriteBytes(session.myseries.gardenData) bf.WriteUint16(c)
c, d := getGookData(s, pkt.CharID) bf.WriteUint16(0)
bf.WriteUint16(c) bf.WriteBytes(d)
bf.WriteUint16(0)
bf.WriteBytes(d)
}
}
} }
if len(bf.Data()) == 0 { if len(bf.Data()) == 0 {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))

View File

@@ -17,12 +17,12 @@ func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) {
s.server.userBinaryPartsLock.Unlock() s.server.userBinaryPartsLock.Unlock()
var exists []byte 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 { 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{ msg := &mhfpacket.MsgSysNotifyUserBinary{
CharID: s.charID, 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 we can't get the real data, try to get it from the database.
if !ok { 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 { if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
} else { } else {