snow/fortnite/external.go

384 lines
9.3 KiB
Go
Raw Normal View History

package fortnite
import (
"encoding/json"
"fmt"
"io"
"net/http"
"slices"
"strings"
"github.com/ectrc/snow/aid"
"github.com/ectrc/snow/storage"
)
var (
2024-02-19 04:07:40 +00:00
DataClient *dataClient
)
2024-02-19 04:07:40 +00:00
type dataClient struct {
h *http.Client
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:"-"`
2024-02-19 01:49:14 +00:00
SnowVariantTokens map[string]*FortniteVariantToken `json:"variants"`
2024-02-19 04:07:40 +00:00
StorefrontCosmeticOfferPriceLookup map[string]map[string]int `json:"-"`
StorefrontDailyItemCountLookup []struct{Season int;Items int} `json:"-"`
StorefrontWeeklySetCountLookup []struct{Season int;Sets int} `json:"-"`
StorefrontCurrencyOfferPriceLookup map[string]map[int]int `json:"-"`
2024-02-19 16:08:37 +00:00
StorefrontCurrencyMultiplier map[string]float64 `json:"-"`
}
2024-02-19 04:07:40 +00:00
func NewDataClient() *dataClient {
return &dataClient{
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),
2024-02-19 01:49:14 +00:00
SnowVariantTokens: make(map[string]*FortniteVariantToken),
2024-02-19 04:07:40 +00:00
StorefrontDailyItemCountLookup: []struct{Season int;Items int}{
{2, 4},
{4, 6},
{13, 10},
},
StorefrontWeeklySetCountLookup: []struct{Season int;Sets int}{
{2, 2},
{4, 3},
{13, 5},
},
StorefrontCosmeticOfferPriceLookup: map[string]map[string]int{
"EFortRarity::Legendary": {
"AthenaCharacter": 2000,
"AthenaBackpack": 1500,
"AthenaPickaxe": 1500,
"AthenaGlider": 1800,
"AthenaDance": 500,
"AthenaItemWrap": 800,
},
"EFortRarity::Epic": {
"AthenaCharacter": 1500,
"AthenaBackpack": 1200,
"AthenaPickaxe": 1200,
"AthenaGlider": 1500,
"AthenaDance": 800,
"AthenaItemWrap": 800,
},
"EFortRarity::Rare": {
"AthenaCharacter": 1200,
"AthenaBackpack": 800,
"AthenaPickaxe": 800,
"AthenaGlider": 800,
"AthenaDance": 500,
"AthenaItemWrap": 600,
},
"EFortRarity::Uncommon": {
"AthenaCharacter": 800,
"AthenaBackpack": 200,
"AthenaPickaxe": 500,
"AthenaGlider": 500,
"AthenaDance": 200,
"AthenaItemWrap": 300,
},
"EFortRarity::Common": {
"AthenaCharacter": 500,
"AthenaBackpack": 200,
"AthenaPickaxe": 500,
"AthenaGlider": 500,
"AthenaDance": 200,
"AthenaItemWrap": 300,
},
},
StorefrontCurrencyOfferPriceLookup: map[string]map[int]int{
"USD": {
1000: 999,
2800: 2499,
5000: 3999,
2024-02-19 16:08:37 +00:00
7500: 5999,
2024-02-19 04:07:40 +00:00
13500: 9999,
},
"GBP": {
1000: 799,
2800: 1999,
5000: 3499,
2024-02-19 16:08:37 +00:00
7500: 4999,
2024-02-19 04:07:40 +00:00
13500: 7999,
},
},
2024-02-19 16:08:37 +00:00
StorefrontCurrencyMultiplier: map[string]float64{
"USD": 1.2503128911,
"GBP": 1.0,
},
}
}
2024-02-19 04:07:40 +00:00
func (c *dataClient) 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)
}
2024-02-19 01:49:14 +00:00
displayAssets := storage.HttpAsset[[]string]("assets.snow.json")
if displayAssets == nil {
return
}
for _, displayAsset := range *displayAssets {
c.AddDisplayAssetToItem(displayAsset)
}
2024-02-19 01:49:14 +00:00
variantTokens := storage.HttpAsset[map[string]SnowCosmeticVariantToken]("variants.snow.json")
if variantTokens == nil {
return
}
2024-02-19 01:49:14 +00:00
for k, v := range *variantTokens {
item := c.FortniteItems[v.Item]
if item == nil {
continue
}
c.SnowVariantTokens[k] = &FortniteVariantToken{
Grants: v.Grants,
Item: item,
Name: v.Name,
Gift: v.Gift,
Equip: v.Equip,
Unseen: v.Unseen,
}
}
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)
}
}
}
2024-02-19 04:07:40 +00:00
func (c *dataClient) 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)
}
2024-02-19 04:07:40 +00:00
func (c *dataClient) 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
}
2024-02-19 04:07:40 +00:00
func (c *dataClient) 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)
}
}
if found == nil {
return
}
found.DisplayAssetPath2 = displayAsset
c.FortniteItemsWithDisplayAssets[found.ID] = found
c.TypedFortniteItemsWithDisplayAssets[found.Type.BackendValue] = append(c.TypedFortniteItemsWithDisplayAssets[found.Type.BackendValue], found)
}
2024-02-19 04:07:40 +00:00
func (c *dataClient) 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,
})
}
2024-02-19 04:07:40 +00:00
func (c *dataClient) GetStorefrontDailyItemCount(season int) int {
currentValue := 4
for _, item := range c.StorefrontDailyItemCountLookup {
if item.Season > season {
continue
}
currentValue = item.Items
}
return currentValue
}
func (c *dataClient) GetStorefrontWeeklySetCount(season int) int {
currentValue := 2
for _, item := range c.StorefrontWeeklySetCountLookup {
if item.Season > season {
continue
}
currentValue = item.Sets
}
return currentValue
}
func (c *dataClient) GetStorefrontCosmeticOfferPrice(rarity string, type_ string) int {
return c.StorefrontCosmeticOfferPriceLookup[rarity][type_]
}
func (c *dataClient) GetStorefrontCurrencyOfferPrice(currency string, amount int) int {
return c.StorefrontCurrencyOfferPriceLookup[currency][amount]
}
2024-02-19 16:08:37 +00:00
func (c *dataClient) GetLocalizedPrice(currency string, amount int) int {
return int(float64(amount) * c.StorefrontCurrencyMultiplier[currency])
}
func PreloadCosmetics() error {
2024-02-19 04:07:40 +00:00
DataClient = NewDataClient()
DataClient.LoadExternalData()
2024-02-19 04:07:40 +00:00
aid.Print("(snow) " + fmt.Sprint(len(DataClient.FortniteItems)) + " cosmetics loaded from fortnite-api.com")
return nil
}
2024-02-18 00:09:02 +00:00
func GetItemByShallowID(shallowID string) *FortniteItem {
2024-02-19 04:07:40 +00:00
for _, item := range DataClient.TypedFortniteItems["AthenaCharacter"] {
if strings.Contains(item.ID, shallowID) {
return item
}
}
return nil
}
2024-02-18 00:09:02 +00:00
func GetRandomItemWithDisplayAsset() *FortniteItem {
2024-02-19 04:07:40 +00:00
items := DataClient.FortniteItemsWithDisplayAssets
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-18 00:09:02 +00:00
return &flat[aid.RandomInt(0, len(flat))]
}
2024-02-18 00:09:02 +00:00
func GetRandomItemWithDisplayAssetOfNotType(notType string) *FortniteItem {
flat := []FortniteItem{}
2024-02-19 04:07:40 +00:00
for t, items := range DataClient.TypedFortniteItemsWithDisplayAssets {
2024-02-18 00:09:02 +00:00
if t == notType {
continue
}
2024-02-18 00:09:02 +00:00
for _, item := range items {
flat = append(flat, *item)
}
}
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-18 00:09:02 +00:00
return &flat[aid.RandomInt(0, len(flat))]
}
2024-02-18 00:09:02 +00:00
func GetRandomSet() *FortniteSet {
sets := []FortniteSet{}
2024-02-19 04:07:40 +00:00
for _, set := range DataClient.FortniteSets {
if set.BackendName == "" {
continue
}
2024-02-18 00:09:02 +00:00
sets = append(sets, *set)
}
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))]
}