mirror of
https://github.com/Walter-Sparrow/lunar-tear.git
synced 2026-07-02 05:43:41 +03:00
94 lines
3.0 KiB
Go
94 lines
3.0 KiB
Go
// Package runtime owns the live, hot-swappable view of master data.
|
|
//
|
|
// The Holder atomically swaps a *Catalogs aggregate every time the operator
|
|
// asks the server to re-read assets/release/20240404193219.bin.e (typically via
|
|
// the admin webhook in cmd/lunar-tear/admin.go). gRPC services hold a *Holder
|
|
// and call Get() at the start of each RPC, so they always see a consistent
|
|
// snapshot.
|
|
package runtime
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"lunar-tear/server/internal/campaign"
|
|
"lunar-tear/server/internal/gacha"
|
|
"lunar-tear/server/internal/masterdata"
|
|
"lunar-tear/server/internal/masterdata/memorydb"
|
|
"lunar-tear/server/internal/model"
|
|
"lunar-tear/server/internal/questflow"
|
|
"lunar-tear/server/internal/store"
|
|
)
|
|
|
|
// Catalogs is an immutable snapshot of every catalog and catalog-derived
|
|
// handler the server needs at runtime. A new *Catalogs is built from scratch
|
|
// on every reload and atomically published via Holder.
|
|
type Catalogs struct {
|
|
GameConfig *masterdata.GameConfig
|
|
Parts *masterdata.PartsCatalog
|
|
Quest *masterdata.QuestCatalog
|
|
GachaEntries []store.GachaCatalogEntry
|
|
GachaMedals map[int32]masterdata.GachaMedalInfo
|
|
GachaPool *masterdata.GachaCatalog
|
|
Shop *masterdata.ShopCatalog
|
|
DupExchange map[int32][]model.DupExchangeEntry
|
|
ConditionResolver *masterdata.ConditionResolver
|
|
CageOrnament *masterdata.CageOrnamentCatalog
|
|
LoginBonus *masterdata.LoginBonusCatalog
|
|
CharacterViewer *masterdata.CharacterViewerCatalog
|
|
Omikuji *masterdata.OmikujiCatalog
|
|
Material *masterdata.MaterialCatalog
|
|
ConsumableItem *masterdata.ConsumableItemCatalog
|
|
Costume *masterdata.CostumeCatalog
|
|
Weapon *masterdata.WeaponCatalog
|
|
Explore *masterdata.ExploreCatalog
|
|
Gimmick *masterdata.GimmickCatalog
|
|
CharacterBoard *masterdata.CharacterBoardCatalog
|
|
CharacterRebirth *masterdata.CharacterRebirthCatalog
|
|
Companion *masterdata.CompanionCatalog
|
|
SideStory *masterdata.SideStoryCatalog
|
|
BigHunt *masterdata.BigHuntCatalog
|
|
Tower *masterdata.TowerCatalog
|
|
Labyrinth *masterdata.LabyrinthCatalog
|
|
Campaign *campaign.Catalog
|
|
|
|
QuestHandler *questflow.QuestHandler
|
|
GachaHandler *gacha.GachaHandler
|
|
}
|
|
|
|
type Holder struct {
|
|
binPath string
|
|
cur atomic.Pointer[Catalogs]
|
|
}
|
|
|
|
func NewHolder(binPath string) (*Holder, error) {
|
|
h := &Holder{binPath: binPath}
|
|
if err := h.Reload(); err != nil {
|
|
return nil, err
|
|
}
|
|
return h, nil
|
|
}
|
|
|
|
func (h *Holder) Reload() error {
|
|
if err := memorydb.Init(h.binPath); err != nil {
|
|
return fmt.Errorf("memorydb.Init: %w", err)
|
|
}
|
|
c, err := buildCatalogs()
|
|
if err != nil {
|
|
return fmt.Errorf("buildCatalogs: %w", err)
|
|
}
|
|
h.cur.Store(c)
|
|
now := time.Now()
|
|
if err := os.Chtimes(h.binPath, now, now); err != nil {
|
|
log.Printf("[runtime] os.Chtimes(%s) failed (clients may not invalidate cache): %v", h.binPath, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (h *Holder) Get() *Catalogs {
|
|
return h.cur.Load()
|
|
}
|