package gameserver import ( "encoding/json" "fmt" "sort" "sync" "gac-hkrpg-go/internal/common" ) // Tutorial IDs come from the installed Client resource tables, not a list // copied from an older server build. Restart after replacing these resources. var tutorialResourceCache struct { sync.Once tutorials []uint32 guides []uint32 err error } func getTutorialResourceIDs() ([]uint32, []uint32, error) { tutorialResourceCache.Do(func() { var tutorialFile struct { Entries []struct { ID uint32 `json:"TutorialID"` } `json:"tutorial_config"` } var guideFile struct { Entries []struct { ID uint32 `json:"GroupID"` } `json:"tutorial_guide_config"` } load := func(name string, dst any) error { path := "resources/" + name data, err := common.ReadResourceFile(path) if err != nil { return fmt.Errorf("tutorial resource %s: %w", path, err) } if err := json.Unmarshal(data, dst); err != nil { return fmt.Errorf("tutorial resource %s: %w", path, err) } return nil } if err := load("TutorialData.json", &tutorialFile); err != nil { tutorialResourceCache.err = err return } if err := load("TutorialGuideGroup.json", &guideFile); err != nil { tutorialResourceCache.err = err return } collect := func(ids []uint32) []uint32 { sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] }) out := ids[:0] for _, id := range ids { if id != 0 && (len(out) == 0 || id != out[len(out)-1]) { out = append(out, id) } } return out } for _, entry := range tutorialFile.Entries { tutorialResourceCache.tutorials = append(tutorialResourceCache.tutorials, entry.ID) } for _, entry := range guideFile.Entries { tutorialResourceCache.guides = append(tutorialResourceCache.guides, entry.ID) } tutorialResourceCache.tutorials = collect(tutorialResourceCache.tutorials) tutorialResourceCache.guides = collect(tutorialResourceCache.guides) if len(tutorialResourceCache.tutorials) == 0 || len(tutorialResourceCache.guides) == 0 { tutorialResourceCache.err = fmt.Errorf("tutorial resource tables contain no IDs") } }) return tutorialResourceCache.tutorials, tutorialResourceCache.guides, tutorialResourceCache.err }