2023-11-21 23:42:39 +00:00
|
|
|
package fortnite
|
|
|
|
|
|
|
|
import (
|
2023-12-03 02:02:19 +00:00
|
|
|
"strings"
|
2023-11-26 22:39:05 +00:00
|
|
|
|
2023-11-21 23:42:39 +00:00
|
|
|
"github.com/ectrc/snow/aid"
|
|
|
|
"github.com/ectrc/snow/person"
|
2023-11-26 22:39:05 +00:00
|
|
|
"github.com/google/uuid"
|
2023-11-21 23:42:39 +00:00
|
|
|
)
|
|
|
|
|
2023-11-26 22:39:05 +00:00
|
|
|
var (
|
|
|
|
Rarities = map[string]int{
|
|
|
|
"EFortRarity::Legendary": 2000,
|
|
|
|
"EFortRarity::Epic": 1500,
|
|
|
|
"EFortRarity::Rare": 1200,
|
|
|
|
"EFortRarity::Uncommon": 800,
|
|
|
|
"EFortRarity::Common": 500,
|
|
|
|
}
|
2023-12-03 02:02:19 +00:00
|
|
|
StaticCatalog = NewCatalog()
|
2023-11-26 22:39:05 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func GetPriceForRarity(rarity string) int {
|
|
|
|
return Rarities[rarity]
|
|
|
|
}
|
|
|
|
|
2023-11-21 23:42:39 +00:00
|
|
|
type Catalog struct {
|
2023-12-03 02:02:19 +00:00
|
|
|
RefreshIntervalHrs int `json:"refreshIntervalHrs"`
|
|
|
|
DailyPurchaseHrs int `json:"dailyPurchaseHrs"`
|
|
|
|
Expiration string `json:"expiration"`
|
2023-11-21 23:42:39 +00:00
|
|
|
Storefronts []Storefront `json:"storefronts"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewCatalog() *Catalog {
|
|
|
|
return &Catalog{
|
|
|
|
RefreshIntervalHrs: 24,
|
|
|
|
DailyPurchaseHrs: 24,
|
|
|
|
Expiration: aid.TimeEndOfDay(),
|
|
|
|
Storefronts: []Storefront{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Catalog) Add(storefront *Storefront) {
|
|
|
|
c.Storefronts = append(c.Storefronts, *storefront)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Catalog) GenerateFortniteCatalog(p *person.Person) aid.JSON {
|
|
|
|
json := aid.JSON{
|
|
|
|
"refreshIntervalHrs": c.RefreshIntervalHrs,
|
|
|
|
"dailyPurchaseHrs": c.DailyPurchaseHrs,
|
|
|
|
"expiration": c.Expiration,
|
|
|
|
"storefronts": []aid.JSON{},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, storefront := range c.Storefronts {
|
|
|
|
json["storefronts"] = append(json["storefronts"].([]aid.JSON), storefront.GenerateResponse(p))
|
|
|
|
}
|
|
|
|
|
|
|
|
return json
|
2023-12-03 15:10:37 +00:00
|
|
|
}
|
2023-11-21 23:42:39 +00:00
|
|
|
|
2023-12-03 20:16:40 +00:00
|
|
|
func (c *Catalog) CheckIfOfferIsDuplicate(entry Entry) bool {
|
2023-12-03 15:10:37 +00:00
|
|
|
for _, storefront := range c.Storefronts {
|
|
|
|
for _, catalogEntry := range storefront.CatalogEntries {
|
|
|
|
if catalogEntry.Grants[0] == entry.Grants[0] {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
2023-11-21 23:42:39 +00:00
|
|
|
}
|
|
|
|
|
2023-12-03 20:16:40 +00:00
|
|
|
func (c *Catalog) GetOfferById(id string) *Entry {
|
|
|
|
for _, storefront := range c.Storefronts {
|
|
|
|
for _, catalogEntry := range storefront.CatalogEntries {
|
|
|
|
if catalogEntry.ID == id {
|
|
|
|
return &catalogEntry
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-11-21 23:42:39 +00:00
|
|
|
type Storefront struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
CatalogEntries []Entry `json:"catalogEntries"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewStorefront(name string) *Storefront {
|
|
|
|
return &Storefront{
|
|
|
|
Name: name,
|
|
|
|
CatalogEntries: []Entry{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Storefront) Add(entry Entry) {
|
|
|
|
s.CatalogEntries = append(s.CatalogEntries, entry)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Storefront) GenerateResponse(p *person.Person) aid.JSON {
|
|
|
|
json := aid.JSON{
|
|
|
|
"name": s.Name,
|
|
|
|
"catalogEntries": []aid.JSON{},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, entry := range s.CatalogEntries {
|
2023-12-03 02:02:19 +00:00
|
|
|
json["catalogEntries"] = append(json["catalogEntries"].([]aid.JSON), entry.GenerateResponse(p))
|
2023-11-21 23:42:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return json
|
|
|
|
}
|
|
|
|
|
|
|
|
type Entry struct {
|
|
|
|
ID string
|
|
|
|
Name string
|
2023-11-26 22:39:05 +00:00
|
|
|
Price int
|
2023-11-21 23:42:39 +00:00
|
|
|
Meta []aid.JSON
|
|
|
|
Panel string
|
|
|
|
Priority int
|
|
|
|
Grants []string
|
2023-11-26 22:39:05 +00:00
|
|
|
DisplayAssetPath string
|
2023-12-03 02:02:19 +00:00
|
|
|
NewDisplayAssetPath string
|
2023-11-26 22:39:05 +00:00
|
|
|
Title string
|
|
|
|
ShortDescription string
|
2023-12-03 20:16:40 +00:00
|
|
|
ProfileType string
|
2023-11-21 23:42:39 +00:00
|
|
|
}
|
|
|
|
|
2023-12-03 20:16:40 +00:00
|
|
|
func NewCatalogEntry(profile string, meta ...aid.JSON) *Entry {
|
2023-11-21 23:42:39 +00:00
|
|
|
return &Entry{
|
2023-11-26 22:39:05 +00:00
|
|
|
ID: uuid.New().String(),
|
|
|
|
Meta: meta,
|
2023-12-03 20:16:40 +00:00
|
|
|
ProfileType: profile,
|
2023-11-21 23:42:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-26 22:39:05 +00:00
|
|
|
func (e *Entry) AddGrant(templateId string) *Entry {
|
|
|
|
e.Grants = append(e.Grants, templateId)
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Entry) AddMeta(key string, value interface{}) *Entry {
|
|
|
|
e.Meta = append(e.Meta, aid.JSON{
|
|
|
|
"Key": key,
|
|
|
|
"Value": value,
|
|
|
|
})
|
|
|
|
return e
|
2023-11-21 23:42:39 +00:00
|
|
|
}
|
|
|
|
|
2023-12-03 02:02:19 +00:00
|
|
|
func (e *Entry) SetTileSize(size string) *Entry {
|
2023-11-26 22:39:05 +00:00
|
|
|
e.Meta = append(e.Meta, aid.JSON{
|
|
|
|
"Key": "TileSize",
|
|
|
|
"Value": size,
|
|
|
|
})
|
|
|
|
return e
|
2023-11-21 23:42:39 +00:00
|
|
|
}
|
|
|
|
|
2023-12-03 02:02:19 +00:00
|
|
|
func (e *Entry) SetPanel(panel string) *Entry {
|
2023-11-26 22:39:05 +00:00
|
|
|
e.Panel = panel
|
|
|
|
return e
|
2023-11-21 23:42:39 +00:00
|
|
|
}
|
|
|
|
|
2023-12-03 02:02:19 +00:00
|
|
|
func (e *Entry) SetSection(sectionId string) *Entry {
|
|
|
|
for _, m := range e.Meta {
|
|
|
|
if m["Key"] == "SectionId" {
|
|
|
|
m["Value"] = sectionId
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-26 22:39:05 +00:00
|
|
|
e.Meta = append(e.Meta, aid.JSON{
|
|
|
|
"Key": "SectionId",
|
|
|
|
"Value": sectionId,
|
|
|
|
})
|
|
|
|
return e
|
2023-11-21 23:42:39 +00:00
|
|
|
}
|
|
|
|
|
2023-12-03 02:02:19 +00:00
|
|
|
func (e *Entry) SetDisplayAsset(asset string) *Entry {
|
|
|
|
displayAsset := "DAv2_Featured_" + asset
|
|
|
|
e.DisplayAssetPath = "/Game/Catalog/DisplayAssets/" + displayAsset + "." + displayAsset
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Entry) IsNewDisplayAssetValid(asset string) bool {
|
|
|
|
newDisplayAsset := "DAv2_" + strings.ReplaceAll(asset, "Athena_Commando_", "")
|
|
|
|
_, exists := KnownDisplayAssets[newDisplayAsset]
|
|
|
|
return exists
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Entry) SetNewDisplayAsset(asset string) *Entry {
|
|
|
|
newDisplayAsset := "DAv2_" + strings.ReplaceAll(asset, "Athena_Commando_", "")
|
|
|
|
e.NewDisplayAssetPath = "/Game/Catalog/NewDisplayAssets/" + newDisplayAsset + "." + newDisplayAsset
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Entry) SetDisplayAssetPath(path string) *Entry {
|
2023-12-03 15:10:37 +00:00
|
|
|
paths := strings.Split(path, "/")
|
|
|
|
id := paths[len(paths)-1]
|
|
|
|
|
|
|
|
e.DisplayAssetPath = "/Game/Catalog/DisplayAssets/" + id + "." + id
|
2023-12-03 02:02:19 +00:00
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Entry) SetNewDisplayAssetPath(path string) *Entry {
|
|
|
|
e.NewDisplayAssetPath = path
|
2023-11-21 23:42:39 +00:00
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
2023-11-26 22:39:05 +00:00
|
|
|
func (e *Entry) SetTitle(title string) *Entry {
|
|
|
|
e.Title = title
|
2023-11-21 23:42:39 +00:00
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
2023-11-26 22:39:05 +00:00
|
|
|
func (e *Entry) SetShortDescription(description string) *Entry {
|
|
|
|
e.ShortDescription = description
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Entry) SetPrice(price int) *Entry {
|
|
|
|
e.Price = price
|
2023-11-21 23:42:39 +00:00
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Entry) GenerateResponse(p *person.Person) aid.JSON {
|
2023-11-26 22:39:05 +00:00
|
|
|
grantStrings := e.Grants
|
|
|
|
for _, grant := range grantStrings {
|
|
|
|
e.Name += grant + "-"
|
|
|
|
}
|
|
|
|
|
2023-12-03 02:02:19 +00:00
|
|
|
if e.NewDisplayAssetPath == "" && len(e.Grants) != 0 {
|
|
|
|
safeTemplateId := strings.ReplaceAll(strings.Split(e.Grants[0], ":")[1], "Athena_Commando_", "")
|
|
|
|
newDisplayAsset := "DAv2_" + safeTemplateId
|
|
|
|
e.NewDisplayAssetPath = "/Game/Catalog/NewDisplayAssets/" + newDisplayAsset + "." + newDisplayAsset
|
|
|
|
}
|
|
|
|
e.AddMeta("NewDisplayAssetPath", e.NewDisplayAssetPath)
|
|
|
|
|
|
|
|
if e.DisplayAssetPath == "" && len(e.Grants) != 0 {
|
|
|
|
displayAsset := "DA_Featured_" + strings.Split(e.Grants[0], ":")[1]
|
|
|
|
e.DisplayAssetPath = "/Game/Catalog/DisplayAssets/" + displayAsset + "." + displayAsset
|
|
|
|
}
|
|
|
|
e.AddMeta("DisplayAssetPath", e.DisplayAssetPath)
|
|
|
|
|
2023-11-21 23:42:39 +00:00
|
|
|
json := aid.JSON{
|
|
|
|
"offerId": e.ID,
|
|
|
|
"devName": e.Name,
|
2023-11-26 22:39:05 +00:00
|
|
|
"offerType": "StaticPrice",
|
2023-11-21 23:42:39 +00:00
|
|
|
"prices": []aid.JSON{
|
|
|
|
{
|
|
|
|
"currencyType": "MtxCurrency",
|
|
|
|
"currencySubType": "Currency",
|
|
|
|
"regularPrice": e.Price,
|
|
|
|
"dynamicRegularPrice": e.Price,
|
|
|
|
"finalPrice": e.Price,
|
|
|
|
"basePrice": e.Price,
|
|
|
|
"saleExpiration": aid.TimeEndOfDay(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"categories": []string{},
|
2023-11-26 22:39:05 +00:00
|
|
|
"catalogGroupPriority": 0,
|
2023-12-03 02:02:19 +00:00
|
|
|
"sortPriority": e.Priority,
|
2023-11-21 23:42:39 +00:00
|
|
|
"dailyLimit": -1,
|
|
|
|
"weeklyLimit": -1,
|
|
|
|
"monthlyLimit": -1,
|
|
|
|
"fufillmentIds": []string{},
|
2023-12-03 02:02:19 +00:00
|
|
|
"filterWeight": 0.0,
|
2023-11-21 23:42:39 +00:00
|
|
|
"appStoreId": []string{},
|
|
|
|
"refundable": false,
|
|
|
|
"itemGrants": []aid.JSON{},
|
|
|
|
"metaInfo": e.Meta,
|
|
|
|
"meta": aid.JSON{},
|
2023-12-03 02:02:19 +00:00
|
|
|
"displayAssetPath": e.DisplayAssetPath,
|
2023-11-26 22:39:05 +00:00
|
|
|
"title": e.Title,
|
|
|
|
"shortDescription": e.ShortDescription,
|
|
|
|
}
|
2023-11-21 23:42:39 +00:00
|
|
|
grants := []aid.JSON{}
|
|
|
|
requirements := []aid.JSON{}
|
|
|
|
meta := []aid.JSON{}
|
|
|
|
|
|
|
|
for _, templateId := range e.Grants {
|
|
|
|
grants = append(grants, aid.JSON{
|
|
|
|
"templateId": templateId,
|
|
|
|
"quantity": 1,
|
|
|
|
})
|
|
|
|
|
|
|
|
if item := p.AthenaProfile.Items.GetItemByTemplateID(templateId); item != nil {
|
|
|
|
requirements = append(requirements, aid.JSON{
|
|
|
|
"requirementType": "DenyOnItemOwnership",
|
|
|
|
"requiredId": item.ID,
|
|
|
|
"minQuantity": 1,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, m := range e.Meta {
|
|
|
|
meta = append(meta, m)
|
|
|
|
json["meta"].(aid.JSON)[m["Key"].(string)] = m["Value"]
|
|
|
|
}
|
|
|
|
|
|
|
|
if e.Panel != "" {
|
|
|
|
json["categories"] = []string{e.Panel}
|
|
|
|
}
|
|
|
|
|
|
|
|
json["itemGrants"] = grants
|
|
|
|
json["requirements"] = requirements
|
|
|
|
json["metaInfo"] = meta
|
|
|
|
|
|
|
|
return json
|
2023-12-03 02:02:19 +00:00
|
|
|
}
|
|
|
|
|
2023-12-06 22:26:42 +00:00
|
|
|
func GenerateRandomStorefront() {
|
2023-12-03 02:02:19 +00:00
|
|
|
storefront := NewCatalog()
|
|
|
|
|
|
|
|
daily := NewStorefront("BRDailyStorefront")
|
|
|
|
weekly := NewStorefront("BRWeeklyStorefront")
|
|
|
|
|
|
|
|
for i := 0; i < 4; i++ {
|
|
|
|
if aid.Config.Fortnite.Season < 14 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
item := Cosmetics.GetRandomItemByType("AthenaCharacter")
|
2023-12-03 20:16:40 +00:00
|
|
|
entry := NewCatalogEntry("athena")
|
2023-12-03 02:02:19 +00:00
|
|
|
entry.SetSection("Daily")
|
|
|
|
|
|
|
|
if !entry.IsNewDisplayAssetValid(item.ID) {
|
|
|
|
i--
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
entry.SetNewDisplayAsset(item.ID)
|
2023-12-03 15:10:37 +00:00
|
|
|
if item.DisplayAssetPath != "" {
|
|
|
|
entry.SetDisplayAssetPath(item.DisplayAssetPath)
|
|
|
|
}
|
2023-12-03 02:02:19 +00:00
|
|
|
entry.SetPrice(GetPriceForRarity(item.Rarity.BackendValue))
|
|
|
|
entry.AddGrant(item.Type.BackendValue + ":" + item.ID)
|
|
|
|
entry.SetTileSize("Normal")
|
|
|
|
entry.Priority = 1
|
|
|
|
|
2023-12-03 20:16:40 +00:00
|
|
|
if item.Backpack != "" {
|
|
|
|
entry.AddGrant("AthenaBackpack:" + item.Backpack)
|
|
|
|
}
|
|
|
|
|
|
|
|
if storefront.CheckIfOfferIsDuplicate(*entry) {
|
2023-12-03 15:10:37 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-12-03 02:02:19 +00:00
|
|
|
daily.Add(*entry)
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < 6; i++ {
|
|
|
|
item := Cosmetics.GetRandomItemByNotType("AthenaCharacter")
|
2023-12-03 20:16:40 +00:00
|
|
|
entry := NewCatalogEntry("athena")
|
2023-12-03 02:02:19 +00:00
|
|
|
entry.SetSection("Daily")
|
|
|
|
|
|
|
|
if !entry.IsNewDisplayAssetValid(item.ID) {
|
|
|
|
i--
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
entry.SetNewDisplayAsset(item.ID)
|
2023-12-03 15:10:37 +00:00
|
|
|
if item.DisplayAssetPath != "" {
|
|
|
|
entry.SetDisplayAssetPath(item.DisplayAssetPath)
|
|
|
|
}
|
2023-12-03 02:02:19 +00:00
|
|
|
entry.SetPrice(GetPriceForRarity(item.Rarity.BackendValue))
|
|
|
|
entry.AddGrant(item.Type.BackendValue + ":" + item.ID)
|
|
|
|
entry.SetTileSize("Small")
|
|
|
|
|
2023-12-03 20:16:40 +00:00
|
|
|
if storefront.CheckIfOfferIsDuplicate(*entry) {
|
2023-12-03 15:10:37 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-12-03 02:02:19 +00:00
|
|
|
daily.Add(*entry)
|
|
|
|
}
|
|
|
|
|
2023-12-03 15:10:37 +00:00
|
|
|
minimum := 8
|
|
|
|
if aid.Config.Fortnite.Season < 14 {
|
|
|
|
minimum = 3
|
|
|
|
}
|
|
|
|
|
2023-12-03 02:02:19 +00:00
|
|
|
setsAdded := 0
|
2023-12-03 15:10:37 +00:00
|
|
|
for len(weekly.CatalogEntries) < minimum || setsAdded < 2 {
|
2023-12-03 02:02:19 +00:00
|
|
|
set := Cosmetics.GetRandomSet()
|
|
|
|
|
|
|
|
itemsAdded := 0
|
|
|
|
itemsToAdd := []*Entry{}
|
|
|
|
for _, item := range set.Items {
|
2023-12-03 20:16:40 +00:00
|
|
|
entry := NewCatalogEntry("athena")
|
2023-12-03 02:02:19 +00:00
|
|
|
entry.SetSection("Featured")
|
|
|
|
entry.SetPanel(set.BackendName)
|
|
|
|
|
|
|
|
if !entry.IsNewDisplayAssetValid(item.ID) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if item.Type.BackendValue == "AthenaCharacter" {
|
|
|
|
entry.SetTileSize("Normal")
|
2023-12-03 15:10:37 +00:00
|
|
|
if aid.Config.Fortnite.Season < 14 {
|
|
|
|
itemsAdded += 1
|
|
|
|
} else {
|
|
|
|
itemsAdded += 2
|
|
|
|
}
|
2023-12-03 02:02:19 +00:00
|
|
|
entry.Priority = 1
|
|
|
|
} else {
|
|
|
|
entry.SetTileSize("Small")
|
|
|
|
itemsAdded += 1
|
|
|
|
}
|
|
|
|
|
|
|
|
entry.SetNewDisplayAsset(item.ID)
|
2023-12-03 15:10:37 +00:00
|
|
|
if item.DisplayAssetPath != "" {
|
|
|
|
entry.SetDisplayAssetPath(item.DisplayAssetPath)
|
|
|
|
}
|
2023-12-03 02:02:19 +00:00
|
|
|
entry.SetPrice(GetPriceForRarity(item.Rarity.BackendValue))
|
|
|
|
entry.AddGrant(item.Type.BackendValue + ":" + item.ID)
|
|
|
|
|
|
|
|
itemsToAdd = append(itemsToAdd, entry)
|
|
|
|
}
|
|
|
|
|
|
|
|
if itemsAdded % 2 != 0 {
|
|
|
|
itemsToAdd = itemsToAdd[:len(itemsToAdd)-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, entry := range itemsToAdd {
|
2023-12-03 20:16:40 +00:00
|
|
|
if storefront.CheckIfOfferIsDuplicate(*entry) {
|
2023-12-03 15:10:37 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-12-03 02:02:19 +00:00
|
|
|
weekly.Add(*entry)
|
|
|
|
}
|
|
|
|
|
|
|
|
setsAdded++
|
|
|
|
}
|
|
|
|
|
|
|
|
storefront.Add(daily)
|
|
|
|
storefront.Add(weekly)
|
|
|
|
|
|
|
|
StaticCatalog = storefront
|
2023-12-03 20:16:40 +00:00
|
|
|
aid.Print("Generated new random storefront")
|
2023-11-21 23:42:39 +00:00
|
|
|
}
|