From 90314fa411d8a8370dfbf0801dd5b0f99da959c1 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 4 Sep 2022 03:19:32 +1000 Subject: [PATCH] rework savedata --- server/channelserver/handlers.go | 12 +- server/channelserver/handlers_character.go | 135 +++++++++++---------- server/channelserver/handlers_data.go | 60 ++++----- server/channelserver/handlers_guild.go | 15 +-- 4 files changed, 101 insertions(+), 121 deletions(-) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 6c49ba0af..e5476ca5f 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -235,17 +235,11 @@ func logoutPlayer(s *Session) { saveData, err := GetCharacterSaveData(s, s.charID) if err != nil { - panic(err) + s.logger.Error("Failed to get savedata") + return } saveData.RP += uint16(rpGained) - transaction, err := s.server.db.Begin() - err = saveData.Save(s, transaction) - if err != nil { - transaction.Rollback() - panic(err) - } else { - transaction.Commit() - } + saveData.Save(s) } func handleMsgSysSetStatus(s *Session, p mhfpacket.MHFPacket) {} diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index b712f960e..aa3ab5e72 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -1,7 +1,6 @@ package channelserver import ( - "database/sql" "encoding/binary" "erupe-ce/network/mhfpacket" @@ -10,120 +9,134 @@ import ( ) const ( - CharacterSaveRPPointer = 0x22D16 + pointerGender = 0x81 // +1 + pointerRP = 0x22D16 // +2 + pointerHouseTier = 0x1FB6C // +5 + pointerHouseData = 0x1FE01 // +195 + pointerBookshelfData = 0x22298 // +5576 + // Gallery data also exists at 0x21578, is this the contest submission? + pointerGalleryData = 0x22320 // +1748 + pointerToreData = 0x1FCB4 // +240 + pointerGardenData = 0x22C58 // +68 + pointerWeaponID = 0x1F60A // +2 + pointerHRP = 0x1FDF6 // +2 + pointerGRP = 0x1FDFC // +4 ) type CharacterSaveData struct { CharID uint32 Name string - RP uint16 IsNewCharacter bool - // Use provided setter/getter - baseSaveData []byte + Gender bool + RP uint16 + HouseTier []byte + HouseData []byte + BookshelfData []byte + GalleryData []byte + ToreData []byte + GardenData []byte + WeaponID uint16 + HRP uint16 + GRP uint32 + GR uint16 + + compSave []byte + decompSave []byte } func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error) { result, err := s.server.db.Query("SELECT id, savedata, is_new_character, name FROM characters WHERE id = $1", charID) - if err != nil { - s.logger.Error("failed to retrieve save data for character", zap.Error(err), zap.Uint32("charID", charID)) + s.logger.Error("Failed to get savedata", zap.Error(err), zap.Uint32("charID", charID)) return nil, err } - defer result.Close() + if !result.Next() { + s.logger.Error("No savedata found", zap.Uint32("charID", charID)) + return nil, err + } saveData := &CharacterSaveData{} - var compressedBaseSave []byte - - if !result.Next() { - s.logger.Error("no results found for character save data", zap.Uint32("charID", charID)) - return nil, err - } - - err = result.Scan(&saveData.CharID, &compressedBaseSave, &saveData.IsNewCharacter, &saveData.Name) - + err = result.Scan(&saveData.CharID, &saveData.compSave, &saveData.IsNewCharacter, &saveData.Name) if err != nil { - s.logger.Error( - "failed to retrieve save data for character", - zap.Error(err), - zap.Uint32("charID", charID), - ) - + s.logger.Error("Failed to scan savedata", zap.Error(err), zap.Uint32("charID", charID)) return nil, err } - if compressedBaseSave == nil { + if saveData.compSave == nil { return saveData, nil } - decompressedBaseSave, err := nullcomp.Decompress(compressedBaseSave) - + err = saveData.Decompress() if err != nil { - s.logger.Error("Failed to decompress savedata from db", zap.Error(err)) + s.logger.Error("Failed to decompress savedata", zap.Error(err)) return nil, err } - saveData.SetBaseSaveData(decompressedBaseSave) - return saveData, nil } -func (save *CharacterSaveData) Save(s *Session, transaction *sql.Tx) error { +func (save *CharacterSaveData) Save(s *Session) { // We need to update the save data byte array before we save it back to the DB save.updateSaveDataWithStruct() - compressedData, err := save.CompressedBaseData(s) - + err := save.Compress() if err != nil { - return err + s.logger.Error("Failed to compress savedata", zap.Error(err)) + return } - updateSQL := "UPDATE characters SET savedata=$1, is_new_character=$3 WHERE id=$2" + updateSQL := `UPDATE characters SET savedata=$1, is_new_character=$3 WHERE id=$2` - if transaction != nil { - _, err = transaction.Exec(updateSQL, compressedData, save.CharID, save.IsNewCharacter) - } else { - _, err = s.server.db.Exec(updateSQL, compressedData, save.CharID, save.IsNewCharacter) - } + _, err = s.server.db.Exec(updateSQL, save.compSave, save.CharID, save.IsNewCharacter) + if err != nil { + s.logger.Error("Failed to update savedata", zap.Error(err), zap.Uint32("charID", save.CharID)) + } +} + +func (save *CharacterSaveData) Compress() error { + var err error + save.compSave, err = nullcomp.Compress(save.decompSave) if err != nil { - s.logger.Error("failed to save character data", zap.Error(err), zap.Uint32("charID", save.CharID)) return err } return nil } -func (save *CharacterSaveData) CompressedBaseData(s *Session) ([]byte, error) { - compressedData, err := nullcomp.Compress(save.baseSaveData) - +func (save *CharacterSaveData) Decompress() error { + var err error + save.decompSave, err = nullcomp.Decompress(save.compSave) if err != nil { - s.logger.Error("failed to compress saveData", zap.Error(err), zap.Uint32("charID", save.CharID)) - return nil, err + return err } - return compressedData, nil + return nil } -func (save *CharacterSaveData) BaseSaveData() []byte { - return save.baseSaveData -} - -func (save *CharacterSaveData) SetBaseSaveData(data []byte) { - save.baseSaveData = data - // After setting the new save byte array, we can extract the values to update our struct - // This will be useful when we save it back, we use the struct values to overwrite the saveData - save.updateStructWithSaveData() -} - -// This will update the save struct with the values stored in the raw savedata arrays +// This will update the character save with the values stored in the save struct func (save *CharacterSaveData) updateSaveDataWithStruct() { rpBytes := make([]byte, 2) binary.LittleEndian.PutUint16(rpBytes, save.RP) - copy(save.baseSaveData[CharacterSaveRPPointer:CharacterSaveRPPointer+2], rpBytes) + copy(save.decompSave[pointerRP:pointerRP+2], rpBytes) } -// This will update the character save struct with the values stored in the raw savedata arrays +// This will update the save struct with the values stored in the character save func (save *CharacterSaveData) updateStructWithSaveData() { - save.RP = binary.LittleEndian.Uint16(save.baseSaveData[CharacterSaveRPPointer : CharacterSaveRPPointer+2]) + if save.decompSave[pointerGender] == 1 { + save.Gender = true + } else { + save.Gender = false + } + save.RP = binary.LittleEndian.Uint16(save.decompSave[pointerRP : pointerRP+2]) + save.HouseTier = save.decompSave[pointerHouseTier : pointerHouseTier+5] + save.HouseData = save.decompSave[pointerHouseData : pointerHouseData+195] + save.BookshelfData = save.decompSave[pointerBookshelfData : pointerBookshelfData+5576] + save.GalleryData = save.decompSave[pointerGalleryData : pointerGalleryData+1748] + save.ToreData = save.decompSave[pointerToreData : pointerToreData+240] + save.GardenData = save.decompSave[pointerGardenData : pointerGardenData+68] + save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[pointerWeaponID : pointerWeaponID+2]) + save.HRP = binary.LittleEndian.Uint16(save.decompSave[pointerHRP : pointerHRP+2]) + save.GRP = binary.LittleEndian.Uint32(save.decompSave[pointerGRP : pointerGRP+4]) } func handleMsgMhfSexChanger(s *Session, p mhfpacket.MHFPacket) { diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go index 8ed55c54a..048aaff73 100644 --- a/server/channelserver/handlers_data.go +++ b/server/channelserver/handlers_data.go @@ -1,7 +1,6 @@ package channelserver import ( - "encoding/binary" "encoding/hex" "erupe-ce/common/stringsupport" "fmt" @@ -26,7 +25,6 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { return } // Var to hold the decompressed savedata for updating the launcher response fields. - var decompressedData []byte if pkt.SaveType == 1 { // Diff-based update. // diffs themselves are also potentially compressed @@ -36,43 +34,35 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { } // Perform diff. s.logger.Info("Diffing...") - characterSaveData.SetBaseSaveData(deltacomp.ApplyDataDiff(diff, characterSaveData.BaseSaveData())) + characterSaveData.decompSave = deltacomp.ApplyDataDiff(diff, characterSaveData.decompSave) } else { + dumpSaveData(s, pkt.RawDataPayload, "savedata") // Regular blob update. saveData, err := nullcomp.Decompress(pkt.RawDataPayload) if err != nil { s.logger.Fatal("Failed to decompress savedata from packet", zap.Error(err)) } s.logger.Info("Updating save with blob") - characterSaveData.SetBaseSaveData(saveData) + characterSaveData.decompSave = saveData } characterSaveData.IsNewCharacter = false - characterBaseSaveData := characterSaveData.BaseSaveData() - // Make a copy for updating the launcher fields. - decompressedData = make([]byte, len(characterBaseSaveData)) - copy(decompressedData, characterBaseSaveData) - err = characterSaveData.Save(s, nil) - if err != nil { - s.logger.Fatal("Failed to update savedata in db", zap.Error(err)) - } + characterSaveData.Save(s) s.logger.Info("Wrote recompressed savedata back to DB.") - dumpSaveData(s, pkt.RawDataPayload, "savedata") - _, err = s.server.db.Exec("UPDATE characters SET weapon_type=$1 WHERE id=$2", uint16(decompressedData[128789]), s.charID) + _, err = s.server.db.Exec("UPDATE characters SET weapon_type=$1 WHERE id=$2", uint16(characterSaveData.decompSave[128789]), s.charID) if err != nil { s.logger.Fatal("Failed to character weapon type in db", zap.Error(err)) } - s.myseries.houseTier = decompressedData[129900:129905] // 0x1FB6C + 5 - s.myseries.houseData = decompressedData[130561:130756] // 0x1FE01 + 195 - s.myseries.bookshelfData = decompressedData[139928:145504] // 0x22298 + 5576 - // Gallery data also exists at 0x21578, is this the contest submission? - s.myseries.galleryData = decompressedData[140064:141812] // 0x22320 + 1748 - s.myseries.toreData = decompressedData[130228:130468] // 0x1FCB4 + 240 - s.myseries.gardenData = decompressedData[142424:142492] // 0x22C58 + 68 + s.myseries.houseTier = characterSaveData.HouseTier + s.myseries.houseData = characterSaveData.HouseData + s.myseries.bookshelfData = characterSaveData.BookshelfData + s.myseries.galleryData = characterSaveData.GalleryData + s.myseries.toreData = characterSaveData.ToreData + s.myseries.gardenData = characterSaveData.GardenData - isFemale := decompressedData[81] // 0x51 - if isFemale == 1 { + isFemale := characterSaveData.Gender + if isFemale { _, err = s.server.db.Exec("UPDATE characters SET is_female=true WHERE id=$1", s.charID) } else { _, err = s.server.db.Exec("UPDATE characters SET is_female=false WHERE id=$1", s.charID) @@ -81,32 +71,26 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { s.logger.Fatal("Failed to character gender in db", zap.Error(err)) } - weaponId := binary.LittleEndian.Uint16(decompressedData[128522:128524]) // 0x1F60A - _, err = s.server.db.Exec("UPDATE characters SET weapon_id=$1 WHERE id=$2", weaponId, s.charID) + _, err = s.server.db.Exec("UPDATE characters SET weapon_id=$1 WHERE id=$2", characterSaveData.WeaponID, s.charID) if err != nil { s.logger.Fatal("Failed to update character weapon id in db", zap.Error(err)) } - hrp := binary.LittleEndian.Uint16(decompressedData[130550:130552]) // 0x1FDF6 - _, err = s.server.db.Exec("UPDATE characters SET hrp=$1 WHERE id=$2", hrp, s.charID) + _, err = s.server.db.Exec("UPDATE characters SET hrp=$1 WHERE id=$2", characterSaveData.HRP, s.charID) if err != nil { s.logger.Fatal("Failed to update character hrp in db", zap.Error(err)) } - grp := binary.LittleEndian.Uint32(decompressedData[130556:130560]) // 0x1FDFC - var gr uint16 - if grp > 0 { - gr = grpToGR(grp) - } else { - gr = 0 + if characterSaveData.GRP > 0 { + characterSaveData.GR = grpToGR(characterSaveData.GRP) } - _, err = s.server.db.Exec("UPDATE characters SET gr=$1 WHERE id=$2", gr, s.charID) + _, err = s.server.db.Exec("UPDATE characters SET gr=$1 WHERE id=$2", characterSaveData.GR, s.charID) if err != nil { s.logger.Fatal("Failed to update character gr in db", zap.Error(err)) } - characterName := s.clientContext.StrConv.MustDecode(bfutil.UpToNull(decompressedData[88:100])) - _, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterName, s.charID) + characterSaveData.Name = s.clientContext.StrConv.MustDecode(bfutil.UpToNull(characterSaveData.decompSave[88:100])) + _, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterSaveData.Name, s.charID) if err != nil { s.logger.Fatal("Failed to update character name in db", zap.Error(err)) } @@ -320,7 +304,7 @@ func handleMsgMhfLoaddata(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveScenarioData(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfSaveScenarioData) - _, err := s.server.db.Exec("UPDATE characters SET scenariodata = $1 WHERE characters.id = $2", pkt.RawDataPayload, int(s.charID)) + _, err := s.server.db.Exec("UPDATE characters SET scenariodata = $1 WHERE id = $2", pkt.RawDataPayload, s.charID) if err != nil { s.logger.Fatal("Failed to update scenario data in db", zap.Error(err)) } @@ -337,7 +321,7 @@ func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfLoadScenarioData) var scenarioData []byte bf := byteframe.NewByteFrame() - err := s.server.db.QueryRow("SELECT scenariodata FROM characters WHERE characters.id = $1", int(s.charID)).Scan(&scenarioData) + err := s.server.db.QueryRow("SELECT scenariodata FROM characters WHERE id = $1", s.charID).Scan(&scenarioData) if err != nil { s.logger.Fatal("Failed to get scenario data contents in db", zap.Error(err)) } else { diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 327f35781..f34005a66 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -725,11 +725,7 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) { rp := uint16(pkt.Data1.ReadUint32()) saveData, _ := GetCharacterSaveData(s, s.charID) saveData.RP -= rp - transaction, err := s.server.db.Begin() - err = saveData.Save(s, transaction) - if err != nil { - transaction.Rollback() - } + saveData.Save(s) bf.WriteUint32(uint32(saveData.RP)) default: panic(fmt.Sprintf("unhandled operate guild action '%d'", pkt.Action)) @@ -763,14 +759,7 @@ func handleDonateRP(s *Session, amount uint16, guild *Guild, isEvent bool) []byt return bf.Data() } saveData.RP -= amount - transaction, err := s.server.db.Begin() - err = saveData.Save(s, transaction) - if err != nil { - transaction.Rollback() - return bf.Data() - } else { - transaction.Commit() - } + saveData.Save(s) updateSQL := "UPDATE guilds SET rank_rp = rank_rp + $1 WHERE id = $2" if isEvent { updateSQL = "UPDATE guilds SET event_rp = event_rp + $1 WHERE id = $2"