2026-10-07 00:21:41 +07:00
|
|
|
package gameserver
|
|
|
|
|
|
2026-10-16 22:19:52 +07:00
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"sort"
|
|
|
|
|
"sync"
|
2026-10-28 18:54:43 +07:00
|
|
|
|
|
|
|
|
"gac-hkrpg-go/internal/common"
|
2026-10-16 22:19:52 +07:00
|
|
|
)
|
2026-10-07 00:21:41 +07:00
|
|
|
|
2026-10-16 22:19:52 +07:00
|
|
|
// 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
|
2026-10-07 00:21:41 +07:00
|
|
|
}
|
|
|
|
|
|
2026-10-16 22:19:52 +07:00
|
|
|
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 {
|
2026-10-28 18:54:43 +07:00
|
|
|
path := "resources/" + name
|
|
|
|
|
data, err := common.ReadResourceFile(path)
|
2026-10-16 22:19:52 +07:00
|
|
|
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
|
2026-10-07 00:21:41 +07:00
|
|
|
}
|