package gameserver import ( "encoding/json" "fmt" "os" "sync" goproto "gac-hkrpg-go/protocol/proto" ) type profileResources struct { Source struct { Revision string `json:"revision"` } `json:"source"` PersonalCards []uint32 `json:"personal_cards"` CurrentPersonalCard uint32 `json:"current_personal_card"` HeadFrame *goproto.HeadFrameInfo `json:"head_frame"` PhoneCases []uint32 `json:"phone_cases"` PhoneThemes []uint32 `json:"phone_themes"` ChatBubbles []uint32 `json:"chat_bubbles"` CurrentPhoneCase uint32 `json:"current_phone_case"` CurrentPhoneTheme uint32 `json:"current_phone_theme"` CurrentChatBubble uint32 `json:"current_chat_bubble"` Icons []uint32 `json:"-"` } var profileOnce sync.Once var profileData profileResources var profileError error func loadProfileResources() (*profileResources, error) { profileOnce.Do(func() { raw, err := os.ReadFile("resources/ProfileConfig.json") if err != nil { profileError = err return } if err := json.Unmarshal(raw, &profileData); err != nil { profileError = err return } if profileData.Source.Revision == "" || profileData.HeadFrame == nil || !containsU32(profileData.PersonalCards, profileData.CurrentPersonalCard) { profileError = fmt.Errorf("profile source, head frame or selected personal card is invalid") return } if !containsU32(profileData.PhoneCases, profileData.CurrentPhoneCase) { profileError = fmt.Errorf("selected phone case is not owned") return } raw, err = os.ReadFile("resources/AvatarPlayerIcon.json") if err != nil { profileError = err return } var icons struct { Entries []struct { ID uint32 `json:"ID"` } `json:"player_icon_config"` } if err := json.Unmarshal(raw, &icons); err != nil { profileError = err return } for _, icon := range icons.Entries { if icon.ID != 0 { profileData.Icons = append(profileData.Icons, icon.ID) } } if len(profileData.Icons) == 0 { profileError = fmt.Errorf("AvatarPlayerIcon.json has no icons") } }) if profileError != nil { return nil, fmt.Errorf("load profile resources: %w", profileError) } return &profileData, nil }