255 lines
7.9 KiB
Go
255 lines
7.9 KiB
Go
package catalogs
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/json"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"sync"
|
||
|
|
)
|
||
|
|
|
||
|
|
var _ = json.RawMessage{}
|
||
|
|
var _ = sync.Mutex{}
|
||
|
|
var _ = os.ReadFile
|
||
|
|
var _ = filepath.Join
|
||
|
|
|
||
|
|
//
|
||
|
|
// Client economy tables (mall commodities, drops, gacha pools/contents/tier rules) imported from the
|
||
|
|
// 4229938 config dump into paths.clientConfigs.
|
||
|
|
// Unlike ClientConfigRepository these tables are optional: a missing or malformed file only disables
|
||
|
|
// the matching feature (mall purchase / gacha draw) instead of refusing to start, because the rest of
|
||
|
|
// the server must keep working when a dump is incomplete.
|
||
|
|
//
|
||
|
|
var (
|
||
|
|
EconomyConfigRepository_cacheLock sync.RWMutex
|
||
|
|
EconomyConfigRepository_cached = false
|
||
|
|
EconomyConfigRepository_entries []any
|
||
|
|
)
|
||
|
|
|
||
|
|
// LoadEconomyConfigRepository loads catalog records from client config directory
|
||
|
|
func LoadEconomyConfigRepository(configDir string) ([]any, error) {
|
||
|
|
EconomyConfigRepository_cacheLock.RLock()
|
||
|
|
if EconomyConfigRepository_cached {
|
||
|
|
defer EconomyConfigRepository_cacheLock.RUnlock()
|
||
|
|
return EconomyConfigRepository_entries, nil
|
||
|
|
}
|
||
|
|
EconomyConfigRepository_cacheLock.RUnlock()
|
||
|
|
|
||
|
|
EconomyConfigRepository_cacheLock.Lock()
|
||
|
|
defer EconomyConfigRepository_cacheLock.Unlock()
|
||
|
|
if EconomyConfigRepository_cached { return EconomyConfigRepository_entries, nil }
|
||
|
|
|
||
|
|
filePath := filepath.Join(configDir, "EconomyConfigRepository.json")
|
||
|
|
data, err := os.ReadFile(filePath)
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
var raw struct {
|
||
|
|
Records []json.RawMessage `json:"records"`
|
||
|
|
}
|
||
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
var result []any
|
||
|
|
for _, item := range raw.Records {
|
||
|
|
var m map[string]any
|
||
|
|
if err := json.Unmarshal(item, &m); err == nil {
|
||
|
|
result = append(result, m)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
EconomyConfigRepository_entries = result
|
||
|
|
EconomyConfigRepository_cached = true
|
||
|
|
return result, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// Forces the (optional) tables to load so the startup log reports what was imported.
|
||
|
|
func EconomyConfigRepository_Warmup() {
|
||
|
|
// Catalog helper EconomyConfigRepository_Warmup
|
||
|
|
}
|
||
|
|
|
||
|
|
func EconomyConfigRepository_TryMallCommodity(id uint32, commodity MallCommodity) bool {
|
||
|
|
// Catalog helper EconomyConfigRepository_TryMallCommodity
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func EconomyConfigRepository_TryDrop(id uint32, drop DropRow) bool {
|
||
|
|
// Catalog helper EconomyConfigRepository_TryDrop
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func EconomyConfigRepository_TryPool(id uint32, pool GachaPool) bool {
|
||
|
|
// Catalog helper EconomyConfigRepository_TryPool
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func EconomyConfigRepository_TryTierRule(id uint32, rule GachaTierRule) bool {
|
||
|
|
// Catalog helper EconomyConfigRepository_TryTierRule
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func EconomyConfigRepository_TryTradeItem(id uint32, item TradeItem) bool {
|
||
|
|
// Catalog helper EconomyConfigRepository_TryTradeItem
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func EconomyConfigRepository_PoolContents(poolId uint32) []GachaContent {
|
||
|
|
// Catalog helper EconomyConfigRepository_PoolContents
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func EconomyConfigRepository_ReadRecords(path string, warnings []string) []any {
|
||
|
|
// Catalog helper EconomyConfigRepository_ReadRecords
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// Dump records may carry fully qualified keys ("LT.ConfigGen.IFoo.Id"), so match on the leaf name.
|
||
|
|
func EconomyConfigRepository_TryProperty(row any, name string, value any) bool {
|
||
|
|
// Catalog helper EconomyConfigRepository_TryProperty
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func EconomyConfigRepository_TryUInt32(row any, name string, result uint32) bool {
|
||
|
|
// Catalog helper EconomyConfigRepository_TryUInt32
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func EconomyConfigRepository_TryDouble(row any, name string, result float64) bool {
|
||
|
|
// Catalog helper EconomyConfigRepository_TryDouble
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func EconomyConfigRepository_ReadBool(row any, name string) bool {
|
||
|
|
// Catalog helper EconomyConfigRepository_ReadBool
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func EconomyConfigRepository_ReadUInt32Array(row any, name string) []uint32 {
|
||
|
|
// Catalog helper EconomyConfigRepository_ReadUInt32Array
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// Item1: [{ "id1": 36211010, "count": 10 }, ...] - every entry is granted.
|
||
|
|
func EconomyConfigRepository_ReadItemList(row any, name string) []any {
|
||
|
|
// Catalog helper EconomyConfigRepository_ReadItemList
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// Item2: [{ "id2": .., "min": .., "max": .. }] - one entry is chosen and rolled inside [min, max].
|
||
|
|
func EconomyConfigRepository_ReadItemRangeList(row any, name string) []any {
|
||
|
|
// Catalog helper EconomyConfigRepository_ReadItemRangeList
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// Item3: [{ "id3": .., "count": 0.00075 }] - 'count' is a relative probability weight.
|
||
|
|
func EconomyConfigRepository_ReadItemWeightList(row any, name string) []any {
|
||
|
|
// Catalog helper EconomyConfigRepository_ReadItemWeightList
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// CostCount: [{ "drawCount": 1, "cost": 100 }, ...]
|
||
|
|
func EconomyConfigRepository_ReadCostList(row any, name string) []any {
|
||
|
|
// Catalog helper EconomyConfigRepository_ReadCostList
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// One mall shelf row. Price is the list price, DiscountPrice the current charge (0 = none).
|
||
|
|
type MallCommodity struct {
|
||
|
|
Id uint32 `json:"id"`
|
||
|
|
MallId uint32 `json:"mallId"`
|
||
|
|
Type uint32 `json:"type"`
|
||
|
|
BindId uint32 `json:"bindId"`
|
||
|
|
ConsumeItemId uint32 `json:"consumeItemId"`
|
||
|
|
Price float64 `json:"price"`
|
||
|
|
DiscountPrice float64 `json:"discountPrice"`
|
||
|
|
DropId uint32 `json:"dropId"`
|
||
|
|
LimitNum uint32 `json:"limitNum"`
|
||
|
|
CommodityBindIds []uint32 `json:"commodityBindIds"`
|
||
|
|
UnitPrice float64 `json:"unitPrice"`
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// One drop row. items are always granted,
|
||
|
|
// picks one entry and a random count in [Min, Max], picks one entry by
|
||
|
|
// relative weight (Item3 carries fractional weights, so they are doubles).
|
||
|
|
//
|
||
|
|
type DropRow struct {
|
||
|
|
Id uint32 `json:"id"`
|
||
|
|
Money float64 `json:"money"`
|
||
|
|
BindingGold float64 `json:"bindingGold"`
|
||
|
|
Guaranteed []any `json:"guaranteed"`
|
||
|
|
Ranged []any `json:"ranged"`
|
||
|
|
Weighted []any `json:"weighted"`
|
||
|
|
IsEmpty bool `json:"isEmpty"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type GachaPool struct {
|
||
|
|
Id uint32 `json:"id"`
|
||
|
|
IsDrop bool `json:"isDrop"`
|
||
|
|
MoneyId uint32 `json:"moneyId"`
|
||
|
|
CommodityId uint32 `json:"commodityId"`
|
||
|
|
GrandTierRuleId uint32 `json:"grandTierRuleId"`
|
||
|
|
Costs []any `json:"costs"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type GachaContent struct {
|
||
|
|
Id uint32 `json:"id"`
|
||
|
|
PoolId uint32 `json:"poolId"`
|
||
|
|
TierRarity uint32 `json:"tierRarity"`
|
||
|
|
DropId uint32 `json:"dropId"`
|
||
|
|
Weight float64 `json:"weight"`
|
||
|
|
Quantity uint32 `json:"quantity"`
|
||
|
|
Quality uint32 `json:"quality"`
|
||
|
|
DuplicateReturnDropId uint32 `json:"duplicateReturnDropId"`
|
||
|
|
DuplicateReturnCount uint32 `json:"duplicateReturnCount"`
|
||
|
|
// SS-tier row: the UI plays the extra grand-prize video for these draws.
|
||
|
|
IsGrandPrize bool `json:"isGrandPrize"`
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// Pity ramp for one tier rule. 1 pools ramp their grand-prize chance
|
||
|
|
// from by every draw
|
||
|
|
// once is reached and guarantee it at .
|
||
|
|
// 0 pools instead pick a tier from the cumulative
|
||
|
|
// table (scale 100000) with no pity at all.
|
||
|
|
//
|
||
|
|
type GachaTierRule struct {
|
||
|
|
Id uint32 `json:"id"`
|
||
|
|
RuleType uint32 `json:"ruleType"`
|
||
|
|
PityThreshold uint32 `json:"pityThreshold"`
|
||
|
|
RampStartDraw uint32 `json:"rampStartDraw"`
|
||
|
|
BaseProbability uint32 `json:"baseProbability"`
|
||
|
|
ProbabilityIncrement uint32 `json:"probabilityIncrement"`
|
||
|
|
GrandPrizeProbability []uint32 `json:"grandPrizeProbability"`
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// One trading-post row. 0 hands out as an
|
||
|
|
// ordinary backpack item, 1 unlocks the wardrobe piece , 3 is a
|
||
|
|
// household collectible (also ) and 2 is a fashion suit that retail only
|
||
|
|
// trades through the order book.
|
||
|
|
//
|
||
|
|
type TradeItem struct {
|
||
|
|
Id uint32 `json:"id"`
|
||
|
|
ItemType uint32 `json:"itemType"`
|
||
|
|
ItemId uint32 `json:"itemId"`
|
||
|
|
Tab uint32 `json:"tab"`
|
||
|
|
FashionId uint32 `json:"fashionId"`
|
||
|
|
FashionSuitId uint32 `json:"fashionSuitId"`
|
||
|
|
MinPrice uint32 `json:"minPrice"`
|
||
|
|
MaxPrice uint32 `json:"maxPrice"`
|
||
|
|
BucketRanges []uint32 `json:"bucketRanges"`
|
||
|
|
// Cheapest price the row is offered at - the floor of its authored bucket ranges.
|
||
|
|
MarketPrice uint32 `json:"marketPrice"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type EconomyConfigRepository_Data struct {
|
||
|
|
Mall map[uint32]MallCommodity `json:"mall"`
|
||
|
|
Drops map[uint32]DropRow `json:"drops"`
|
||
|
|
Pools map[uint32]GachaPool `json:"pools"`
|
||
|
|
TierRules map[uint32]GachaTierRule `json:"tierRules"`
|
||
|
|
ContentsByPool map[uint32][]GachaContent `json:"contentsByPool"`
|
||
|
|
TradeItems map[uint32]TradeItem `json:"tradeItems"`
|
||
|
|
}
|
||
|
|
|