package gameserver import ( "encoding/json" "fmt" "strings" "sync" "gac-hkrpg-go/internal/common" ) var navigationProfilesOnce sync.Once var navigationProfilesData []byte var navigationProfilesError error // Quote Lua text without interpreting either Lua escapes or localized labels. func luaNavigationString(value string) string { separator := "" for strings.Contains(value, "]"+separator+"]") { separator += "=" } return "[" + separator + "[" + value + "]" + separator + "]" } func loadNavigationProfiles() ([]byte, error) { navigationProfilesOnce.Do(func() { var data struct { ClientVersion string `json:"client_version"` Profiles []struct { FloorID uint32 `json:"floor_id"` TownEntryID uint32 `json:"town_entry_id"` StoryEntryID uint32 `json:"story_entry_id"` StoryLabel string `json:"story_label"` } `json:"profiles"` } raw, err := common.ReadResourceFile("resources/NavigationProfiles.json") if err != nil { navigationProfilesError = err return } if err = json.Unmarshal(raw, &data); err != nil { navigationProfilesError = err return } cfg, err := common.LoadRuntimeConfig() if err != nil { navigationProfilesError = err return } if data.ClientVersion != cfg.ClientVersion { navigationProfilesError = fmt.Errorf("navigation profiles Client revision mismatch") return } res, err := common.GameRes() if err != nil { navigationProfilesError = err return } var script strings.Builder script.WriteString("\n_G.__GAC_NAVIGATION_PROFILES = {\n") seen := map[uint32]bool{} for _, p := range data.Profiles { town, townOK := res.MapEntrances[p.TownEntryID] story, storyOK := res.MapEntrances[p.StoryEntryID] if !townOK || !storyOK || p.FloorID == 0 || town.FloorID != p.FloorID || story.FloorID != p.FloorID || town.PlaneID != story.PlaneID || town.EntranceType != "Town" || story.EntranceType != "Mission" || p.TownEntryID == p.StoryEntryID || strings.TrimSpace(p.StoryLabel) == "" || seen[p.FloorID] || len(res.LevelOutputConfigs[p.TownEntryID]) == 0 || len(res.LevelOutputConfigs[p.StoryEntryID]) == 0 { navigationProfilesError = fmt.Errorf("invalid navigation profile for floor %d", p.FloorID) return } seen[p.FloorID] = true fmt.Fprintf(&script, "{floor_id=%d,town_entry_id=%d,story_entry_id=%d,story_label=%s},\n", p.FloorID, p.TownEntryID, p.StoryEntryID, luaNavigationString(p.StoryLabel)) } script.WriteString("}\n") navigationProfilesData = []byte(script.String()) }) return navigationProfilesData, navigationProfilesError }