2024-02-11 00:27:08 +00:00
|
|
|
package fortnite
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"slices"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/ectrc/snow/aid"
|
|
|
|
"github.com/ectrc/snow/storage"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
External *ExternalDataClient
|
|
|
|
)
|
|
|
|
|
|
|
|
type ExternalDataClient struct {
|
|
|
|
h *http.Client
|
2024-02-11 18:33:57 +00:00
|
|
|
FortniteSets map[string]*FortniteSet `json:"sets"`
|
|
|
|
FortniteItems map[string]*FortniteItem `json:"items"`
|
|
|
|
FortniteItemsWithDisplayAssets map[string]*FortniteItem `json:"-"`
|
|
|
|
FortniteItemsWithFeaturedImage []*FortniteItem `json:"-"`
|
|
|
|
TypedFortniteItems map[string][]*FortniteItem `json:"-"`
|
|
|
|
TypedFortniteItemsWithDisplayAssets map[string][]*FortniteItem `json:"-"`
|
|
|
|
SnowVariantTokens map[string]SnowCosmeticVariantToken `json:"-"`
|
2024-02-11 00:27:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewExternalDataClient() *ExternalDataClient {
|
|
|
|
return &ExternalDataClient{
|
|
|
|
h: &http.Client{},
|
|
|
|
FortniteItems: make(map[string]*FortniteItem),
|
|
|
|
FortniteSets: make(map[string]*FortniteSet),
|
|
|
|
FortniteItemsWithDisplayAssets: make(map[string]*FortniteItem),
|
|
|
|
FortniteItemsWithFeaturedImage: []*FortniteItem{},
|
|
|
|
TypedFortniteItems: make(map[string][]*FortniteItem),
|
|
|
|
TypedFortniteItemsWithDisplayAssets: make(map[string][]*FortniteItem),
|
|
|
|
SnowVariantTokens: make(map[string]SnowCosmeticVariantToken),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ExternalDataClient) LoadExternalData() {
|
|
|
|
req, err := http.NewRequest("GET", "https://fortnite-api.com/v2/cosmetics/br", nil)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := c.h.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
bodyBytes, err := io.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
content := &FortniteCosmeticsResponse{}
|
|
|
|
err = json.Unmarshal(bodyBytes, content)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, item := range content.Data {
|
|
|
|
c.LoadItem(&item)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, item := range c.TypedFortniteItems["AthenaBackpack"] {
|
|
|
|
c.AddBackpackToItem(item)
|
|
|
|
}
|
|
|
|
|
|
|
|
displayAssets := storage.HttpAsset[[]string]("QKnwROGzQjYm1W9xu9uL3VrbSA0tnVj6NJJtEChUdAb3DF8uN.json")
|
|
|
|
if displayAssets == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, displayAsset := range *displayAssets {
|
|
|
|
c.AddDisplayAssetToItem(displayAsset)
|
|
|
|
}
|
|
|
|
|
|
|
|
variantTokens := storage.HttpAsset[map[string]SnowCosmeticVariantToken]("QF3nHCFt1vhELoU4q1VKTmpxnk20c2iAiBEBzlbzQAY.json")
|
|
|
|
if variantTokens == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
c.SnowVariantTokens = *variantTokens
|
|
|
|
|
|
|
|
addNumericStylesToSets := []string{"Soccer", "Football", "ScaryBall"}
|
|
|
|
for _, setValue := range addNumericStylesToSets {
|
|
|
|
set, found := c.FortniteSets[setValue]
|
|
|
|
if !found {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, item := range set.Items {
|
|
|
|
c.AddNumericStylesToItem(item)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ExternalDataClient) LoadItem(item *FortniteItem) {
|
|
|
|
if item.Introduction.BackendValue > aid.Config.Fortnite.Season || item.Introduction.BackendValue == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.FortniteSets[item.Set.BackendValue] == nil {
|
|
|
|
c.FortniteSets[item.Set.BackendValue] = &FortniteSet{
|
|
|
|
BackendName: item.Set.Value,
|
|
|
|
DisplayName: item.Set.Text,
|
|
|
|
Items: []*FortniteItem{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.TypedFortniteItems[item.Type.BackendValue] == nil {
|
|
|
|
c.TypedFortniteItems[item.Type.BackendValue] = []*FortniteItem{}
|
|
|
|
}
|
|
|
|
|
|
|
|
c.FortniteItems[item.ID] = item
|
|
|
|
c.FortniteSets[item.Set.BackendValue].Items = append(c.FortniteSets[item.Set.BackendValue].Items, item)
|
|
|
|
c.TypedFortniteItems[item.Type.BackendValue] = append(c.TypedFortniteItems[item.Type.BackendValue], item)
|
|
|
|
|
|
|
|
if item.Type.BackendValue != "AthenaCharacter" || item.Images.Featured == "" || slices.Contains[[]string]([]string{
|
|
|
|
"Soccer",
|
|
|
|
"Football",
|
|
|
|
"Waypoint",
|
|
|
|
}, item.Set.BackendValue) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tag := range item.GameplayTags {
|
|
|
|
if strings.Contains(tag, "StarterPack") {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
c.FortniteItemsWithFeaturedImage = append(c.FortniteItemsWithFeaturedImage, item)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ExternalDataClient) AddBackpackToItem(backpack *FortniteItem) {
|
|
|
|
if backpack.ItemPreviewHeroPath == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
splitter := strings.Split(backpack.ItemPreviewHeroPath, "/")
|
|
|
|
character, found := c.FortniteItems[splitter[len(splitter) - 1]]
|
|
|
|
if !found {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
character.Backpack = backpack
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ExternalDataClient) AddDisplayAssetToItem(displayAsset string) {
|
|
|
|
split := strings.Split(displayAsset, "_")[1:]
|
|
|
|
found := c.FortniteItems[strings.Join(split[:], "_")]
|
|
|
|
|
|
|
|
if found == nil && split[0] == "CID" {
|
|
|
|
r := aid.Regex(strings.Join(split[:], "_"), `(?:CID_)(\d+|A_\d+)(?:_.+)`)
|
|
|
|
if r != nil {
|
2024-02-18 00:09:02 +00:00
|
|
|
found = GetItemByShallowID(*r)
|
2024-02-11 00:27:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if found == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
found.DisplayAssetPath2 = displayAsset
|
|
|
|
c.FortniteItemsWithDisplayAssets[found.ID] = found
|
|
|
|
c.TypedFortniteItemsWithDisplayAssets[found.Type.BackendValue] = append(c.TypedFortniteItemsWithDisplayAssets[found.Type.BackendValue], found)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ExternalDataClient) AddNumericStylesToItem(item *FortniteItem) {
|
|
|
|
ownedStyles := []FortniteVariantChannel{}
|
|
|
|
for i := 0; i < 100; i++ {
|
|
|
|
ownedStyles = append(ownedStyles, FortniteVariantChannel{
|
|
|
|
Tag: fmt.Sprint(i),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
item.Variants = append(item.Variants, FortniteVariant{
|
|
|
|
Channel: "Numeric",
|
|
|
|
Type: "int",
|
|
|
|
Options: ownedStyles,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func PreloadCosmetics() error {
|
|
|
|
External = NewExternalDataClient()
|
|
|
|
External.LoadExternalData()
|
|
|
|
|
|
|
|
aid.Print("(snow) " + fmt.Sprint(len(External.FortniteItems)) + " cosmetics loaded from fortnite-api.com")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-02-18 00:09:02 +00:00
|
|
|
func GetItemByShallowID(shallowID string) *FortniteItem {
|
2024-02-11 00:27:08 +00:00
|
|
|
for _, item := range External.TypedFortniteItems["AthenaCharacter"] {
|
|
|
|
if strings.Contains(item.ID, shallowID) {
|
|
|
|
return item
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-02-18 00:09:02 +00:00
|
|
|
func GetRandomItemWithDisplayAsset() *FortniteItem {
|
|
|
|
items := External.FortniteItemsWithDisplayAssets
|
2024-02-11 00:27:08 +00:00
|
|
|
if len(items) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-02-18 00:09:02 +00:00
|
|
|
flat := []FortniteItem{}
|
|
|
|
for _, item := range items {
|
|
|
|
flat = append(flat, *item)
|
|
|
|
}
|
|
|
|
|
|
|
|
slices.SortFunc[[]FortniteItem](flat, func(a, b FortniteItem) int {
|
|
|
|
return strings.Compare(a.ID, b.ID)
|
|
|
|
})
|
2024-02-11 00:27:08 +00:00
|
|
|
|
2024-02-18 00:09:02 +00:00
|
|
|
return &flat[aid.RandomInt(0, len(flat))]
|
|
|
|
}
|
2024-02-11 00:27:08 +00:00
|
|
|
|
2024-02-18 00:09:02 +00:00
|
|
|
func GetRandomItemWithDisplayAssetOfNotType(notType string) *FortniteItem {
|
|
|
|
flat := []FortniteItem{}
|
|
|
|
|
|
|
|
for t, items := range External.TypedFortniteItemsWithDisplayAssets {
|
|
|
|
if t == notType {
|
2024-02-11 00:27:08 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2024-02-18 00:09:02 +00:00
|
|
|
for _, item := range items {
|
|
|
|
flat = append(flat, *item)
|
|
|
|
}
|
2024-02-11 00:27:08 +00:00
|
|
|
}
|
|
|
|
|
2024-02-18 00:09:02 +00:00
|
|
|
slices.SortFunc[[]FortniteItem](flat, func(a, b FortniteItem) int {
|
|
|
|
return strings.Compare(a.ID, b.ID)
|
|
|
|
})
|
2024-02-11 00:27:08 +00:00
|
|
|
|
2024-02-18 00:09:02 +00:00
|
|
|
return &flat[aid.RandomInt(0, len(flat))]
|
2024-02-11 00:27:08 +00:00
|
|
|
}
|
|
|
|
|
2024-02-18 00:09:02 +00:00
|
|
|
func GetRandomSet() *FortniteSet {
|
|
|
|
sets := []FortniteSet{}
|
2024-02-11 00:27:08 +00:00
|
|
|
for _, set := range External.FortniteSets {
|
2024-02-18 00:09:02 +00:00
|
|
|
sets = append(sets, *set)
|
2024-02-11 00:27:08 +00:00
|
|
|
}
|
|
|
|
|
2024-02-18 00:09:02 +00:00
|
|
|
slices.SortFunc[[]FortniteSet](sets, func(a, b FortniteSet) int {
|
|
|
|
return strings.Compare(a.BackendName, b.BackendName)
|
|
|
|
})
|
|
|
|
|
|
|
|
return &sets[aid.RandomInt(0, len(sets))]
|
2024-02-11 00:27:08 +00:00
|
|
|
}
|