Implement hunting AP and progress, event tasks, exchanges, games, stories and actions; connect battle and reward handling. Add CashShop plugin and installation, server purchases and entitlements, recharge rules and plugin version metadata. Distribute binary calendars independently; cache GameData in memory and fix single-connection query deadlocks. Improve automatic login and recovery diagnostics; document configuration and release flows.
60 lines
2.1 KiB
Go
60 lines
2.1 KiB
Go
package gamedata
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
)
|
|
|
|
// BattleDeckForDifficulty mirrors QuicklyQuestHelper.GetBattleDeckIdByDifficulty
|
|
// for the three story difficulties, and verifies the resulting design row.
|
|
// Already-selected difficulty decks retain their ID.
|
|
func BattleDeckForDifficulty(root, version string, packID int, deckID, difficulty uint64) (uint64, error) {
|
|
db, cleanup, err := openPackDatabase(root, version, packID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer cleanup()
|
|
return battleDeckForDifficultyFromDB(db, deckID, difficulty)
|
|
}
|
|
|
|
func openPackDatabase(root, version string, packID int) (*sql.DB, func(), error) {
|
|
if packID <= 0 {
|
|
return nil, nil, fmt.Errorf("gamedata: invalid battle pack %d", packID)
|
|
}
|
|
return OpenDatabase(root, version, fmt.Sprintf("pack%d", packID))
|
|
}
|
|
|
|
func battleDeckForDifficultyFromDB(db *sql.DB, deckID, difficulty uint64) (uint64, error) {
|
|
if deckID == 0 || deckID > 2147483647 || difficulty > 2 {
|
|
return 0, fmt.Errorf("gamedata: unsupported battle deck/difficulty %d/%d", deckID, difficulty)
|
|
}
|
|
var data []byte
|
|
if err := db.QueryRow("SELECT ProtoBuf FROM BattleDeckTable WHERE id=?", deckID).Scan(&data); err != nil {
|
|
return 0, fmt.Errorf("gamedata: battle deck %d: %w", deckID, err)
|
|
}
|
|
actual, err := phaseScalar(data, 24)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if actual == difficulty {
|
|
return deckID, nil
|
|
}
|
|
// Only an ordinary deck can be promoted. Changing a previously selected
|
|
// difficulty deck would conceal stale client quest state.
|
|
if actual != 0 || difficulty == 0 {
|
|
return 0, fmt.Errorf("gamedata: deck %d difficulty %d differs from selected %d", deckID, actual, difficulty)
|
|
}
|
|
selected := deckID + difficulty*100000
|
|
if err := db.QueryRow("SELECT ProtoBuf FROM BattleDeckTable WHERE id=?", selected).Scan(&data); err != nil {
|
|
return 0, fmt.Errorf("gamedata: difficulty deck %d: %w", selected, err)
|
|
}
|
|
actual, err = phaseScalar(data, 24)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if actual != difficulty {
|
|
return 0, fmt.Errorf("gamedata: difficulty deck %d has difficulty %d, want %d", selected, actual, difficulty)
|
|
}
|
|
return selected, nil
|
|
}
|