Files
bd2/go/internal/server/gamedata/avatar_rewards.go
T
Flechazo 924a42c32e fix(all): complete activity calendars, shop purchases and reward dispatch
Restore event and mini hubs, current shop and hunt calendars, and regular seasons; preserve all published windows. Implement story/quiz routes, native shop purchases, avatar sets, currencies, rank-change items and permanent buffs with rollback and reward coverage tests. Refresh client buff stats and update Cash Shop to 0.1.1.
2026-10-05 15:49:50 +08:00

90 lines
2.6 KiB
Go

package gamedata
import (
"database/sql"
"fmt"
"math"
)
// Avatar sets are design bundles: ownership is checked on each member by the
// client, rather than on a synthetic AvatarSet ItemDBInfo.
type AvatarRewardDesign struct {
Sets map[uint64][]BattleReward
Items map[uint64]map[uint64]bool
}
func LoadAvatarRewardDesign(root, version string) (*AvatarRewardDesign, error) {
db, done, err := openStatDatabase(root, version)
if err != nil {
return nil, err
}
defer done()
return loadAvatarRewardDesign(db)
}
func loadAvatarRewardDesign(db *sql.DB) (*AvatarRewardDesign, error) {
d := &AvatarRewardDesign{Sets: map[uint64][]BattleReward{}, Items: map[uint64]map[uint64]bool{49: {}, 50: {}, 61: {}}}
for _, table := range []struct {
name string
typ uint64
field int
}{{"AvatarItemTable", 49, 3}, {"AvatarMotionTable", 50, 5}, {"AvatarCharTable", 61, 6}} {
if err := readCashMetadata(db, table.name, func(raw []byte) error {
id, err := optionalScalar(raw, table.field)
if err != nil {
return err
}
if id == 0 {
return fmt.Errorf("gamedata: invalid avatar member")
}
d.Items[table.typ][id] = true
return nil
}); err != nil {
return nil, err
}
}
if err := readCashMetadata(db, "AvatarSetTable", func(raw []byte) error {
id, err := optionalScalar(raw, 6)
if err != nil {
return err
}
members, err := eventGameRewards(raw, 5, 4, 3)
if err != nil || id == 0 || len(members) == 0 {
return fmt.Errorf("gamedata: invalid avatar set")
}
for _, member := range members {
if !d.Items[member.Type][member.ID] || member.Count == 0 || member.Count > math.MaxInt32 {
return fmt.Errorf("gamedata: avatar set %d has invalid member %d:%d", id, member.Type, member.ID)
}
}
d.Sets[id] = members
return nil
}); err != nil {
return nil, err
}
return d, nil
}
func (d *AvatarRewardDesign) Expand(rewards []BattleReward) ([]BattleReward, error) {
var out []BattleReward
for _, reward := range rewards {
if reward.Type != 62 {
out = append(out, reward)
continue
}
if d == nil || reward.Count == 0 || reward.Count > math.MaxInt32 {
return nil, fmt.Errorf("gamedata: avatar reward design or quantity unavailable")
}
members, ok := d.Sets[reward.ID]
if !ok || len(members) == 0 {
return nil, fmt.Errorf("gamedata: unknown avatar set %d", reward.ID)
}
for _, member := range members {
if !d.Items[member.Type][member.ID] || member.Count == 0 || member.Count > math.MaxInt32/reward.Count {
return nil, fmt.Errorf("gamedata: invalid avatar set member")
}
member.Count *= reward.Count
out = append(out, member)
}
}
return out, nil
}