chore: checkpoint stable battle and eidolon progression
This commit is contained in:
1 parent
365e66ffe0
commit
a681affdb3
23 files changed
+34511
-11310
No files matched your search
@@ -0,0 +1,122 @@
|
||||
package gameserver
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"gac-hkrpg-go/internal/common"
|
||||
goproto "gac-hkrpg-go/protocol/proto"
|
||||
)
|
||||
|
||||
type eidolonResources struct {
|
||||
Avatars map[uint32]struct {
|
||||
MaxRank uint32 `json:"max_rank"`
|
||||
Ranks []struct {
|
||||
Rank uint32 `json:"rank"`
|
||||
Cost []struct {
|
||||
ItemID uint32
|
||||
ItemNum uint32
|
||||
} `json:"cost"`
|
||||
} `json:"ranks"`
|
||||
} `json:"avatars"`
|
||||
ExMaterials map[uint32]struct {
|
||||
ItemID uint32 `json:"item_id"`
|
||||
Count uint32 `json:"count"`
|
||||
} `json:"ex_materials"`
|
||||
}
|
||||
|
||||
var eidolonOnce sync.Once
|
||||
var eidolonData eidolonResources
|
||||
var eidolonError error
|
||||
|
||||
func loadEidolonResources() (*eidolonResources, error) {
|
||||
eidolonOnce.Do(func() {
|
||||
raw, err := common.ReadResourceFile("resources/EidolonConfig.json", "EidolonConfig.json")
|
||||
if err != nil {
|
||||
eidolonError = err
|
||||
return
|
||||
}
|
||||
if err := json.Unmarshal(raw, &eidolonData); err != nil {
|
||||
eidolonError = err
|
||||
return
|
||||
}
|
||||
for id, avatar := range eidolonData.Avatars {
|
||||
if id == 0 || avatar.MaxRank == 0 || len(avatar.Ranks) != int(avatar.MaxRank) {
|
||||
eidolonError = fmt.Errorf("invalid Eidolon ranks for avatar %d", id)
|
||||
return
|
||||
}
|
||||
seen := map[uint32]bool{}
|
||||
for _, rank := range avatar.Ranks {
|
||||
if rank.Rank == 0 || rank.Rank > avatar.MaxRank || seen[rank.Rank] || len(rank.Cost) == 0 {
|
||||
eidolonError = fmt.Errorf("invalid rank costs for avatar %d", id)
|
||||
return
|
||||
}
|
||||
seen[rank.Rank] = true
|
||||
for _, cost := range rank.Cost {
|
||||
if cost.ItemID == 0 || cost.ItemNum == 0 {
|
||||
eidolonError = fmt.Errorf("empty rank cost for avatar %d", id)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for id, material := range eidolonData.ExMaterials {
|
||||
if common.AvatarExRankMap[id] == 0 || material.ItemID == 0 || material.Count == 0 {
|
||||
eidolonError = fmt.Errorf("invalid EX material for avatar %d", id)
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
if eidolonError != nil {
|
||||
return nil, fmt.Errorf("load EidolonConfig.json: %w", eidolonError)
|
||||
}
|
||||
return &eidolonData, nil
|
||||
}
|
||||
|
||||
// The configured sandbox grant covers the remaining ranks. Its remaining
|
||||
// quantity follows saved progression, so reconnecting does not refill used ranks.
|
||||
func eidolonMaterials(player *common.FreesrData) ([]*goproto.Material, error) {
|
||||
resources, err := loadEidolonResources()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
counts := map[uint32]uint32{}
|
||||
for id, rules := range resources.Avatars {
|
||||
avatar := player.Avatars[id]
|
||||
if avatar == nil {
|
||||
continue
|
||||
}
|
||||
for _, rank := range rules.Ranks {
|
||||
for _, cost := range rank.Cost {
|
||||
if _, present := counts[cost.ItemID]; !present {
|
||||
counts[cost.ItemID] = 0
|
||||
}
|
||||
if rank.Rank > avatar.Data.Rank {
|
||||
counts[cost.ItemID] += cost.ItemNum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for id, grant := range resources.ExMaterials {
|
||||
avatar := player.Avatars[id]
|
||||
if avatar == nil {
|
||||
continue
|
||||
}
|
||||
counts[grant.ItemID] = 0
|
||||
if !avatar.ExRankUnlocked {
|
||||
counts[grant.ItemID] = grant.Count
|
||||
}
|
||||
}
|
||||
ids := make([]uint32, 0, len(counts))
|
||||
for id := range counts {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] })
|
||||
var materials []*goproto.Material
|
||||
for _, id := range ids {
|
||||
materials = append(materials, &goproto.Material{Tid: id, Num: counts[id]})
|
||||
}
|
||||
return materials, nil
|
||||
}
|
||||
Reference in new issue
Block a user