Files
bd2/go/internal/server/gamedata/limited_costume.go
T
Flechazo d8771caef2 feat(all): add hunting and events, commerce and rewards, binary calendars, GameData caching and login diagnostics
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.
2026-10-05 11:50:31 +08:00

89 lines
2.2 KiB
Go

package gamedata
import (
"errors"
"fmt"
_ "modernc.org/sqlite"
)
// LimitedCostumeCatalog is the authoritative LimitedCostumeTable membership
// plus the character/growth design required to grant those costumes. It is a
// reward lookup only and never changes any gacha pool.
type LimitedCostumeCatalog struct {
ids []uint64
characters map[uint64]CharacterDesign
}
func LoadLimitedCostumes(root, version string) (*LimitedCostumeCatalog, error) {
db, release, err := OpenDatabase(root, version, "common")
if err != nil {
return nil, err
}
defer release()
rows, err := db.Query("SELECT id FROM LimitedCostumeTable ORDER BY id")
if err != nil {
return nil, err
}
defer rows.Close()
catalog := &LimitedCostumeCatalog{characters: map[uint64]CharacterDesign{}}
for rows.Next() {
var costumeID uint64
if err := rows.Scan(&costumeID); err != nil {
return nil, err
}
if costumeID == 0 {
return nil, errors.New("gamedata: limited costume has zero id")
}
catalog.ids = append(catalog.ids, costumeID)
}
if err := rows.Err(); err != nil {
return nil, err
}
// Release the single connection before character loading performs queries.
if err := rows.Close(); err != nil {
return nil, err
}
if len(catalog.ids) == 0 {
return nil, errors.New("gamedata: limited costume catalog is empty")
}
for _, costumeID := range catalog.ids {
design, err := loadGachaCharacterDesign(db, costumeID)
if err != nil {
return nil, fmt.Errorf("gamedata: limited costume %d: %w", costumeID, err)
}
catalog.characters[costumeID] = design
}
return catalog, nil
}
func (c *LimitedCostumeCatalog) IDs() []uint64 {
if c == nil {
return nil
}
return append([]uint64(nil), c.ids...)
}
func (c *LimitedCostumeCatalog) Character(costumeID uint64) (CharacterDesign, bool) {
if c == nil {
return CharacterDesign{}, false
}
design, ok := c.characters[costumeID]
return design, ok
}
// Excluding returns stable LimitedCostumeTable order without the supplied
// currently featured pickup costume IDs.
func (c *LimitedCostumeCatalog) Excluding(excluded map[uint64]bool) []uint64 {
if c == nil {
return nil
}
ids := make([]uint64, 0, len(c.ids))
for _, id := range c.ids {
if !excluded[id] {
ids = append(ids, id)
}
}
return ids
}