snow/fortnite/shop.go

360 lines
8.5 KiB
Go
Raw Normal View History

2023-11-21 23:42:39 +00:00
package fortnite
import (
2024-02-18 00:09:02 +00:00
"math/rand"
"regexp"
2023-11-21 23:42:39 +00:00
"github.com/ectrc/snow/aid"
"github.com/google/uuid"
2023-11-21 23:42:39 +00:00
)
var (
2024-02-18 00:09:02 +00:00
priceLookup = map[string]map[string]int{
"EFortRarity::Legendary": {
2024-01-21 00:46:06 +00:00
"AthenaCharacter": 2000,
2024-02-18 00:09:02 +00:00
"AthenaBackpack": 1500,
"AthenaPickaxe": 1500,
"AthenaGlider": 1800,
"AthenaDance": 500,
"AthenaItemWrap": 800,
2024-01-21 00:46:06 +00:00
},
"EFortRarity::Epic": {
2024-01-21 00:46:06 +00:00
"AthenaCharacter": 1500,
2024-02-18 00:09:02 +00:00
"AthenaBackpack": 1200,
"AthenaPickaxe": 1200,
"AthenaGlider": 1500,
"AthenaDance": 800,
"AthenaItemWrap": 800,
2024-01-21 00:46:06 +00:00
},
"EFortRarity::Rare": {
2024-01-21 00:46:06 +00:00
"AthenaCharacter": 1200,
2024-02-18 00:09:02 +00:00
"AthenaBackpack": 800,
"AthenaPickaxe": 800,
"AthenaGlider": 800,
"AthenaDance": 500,
"AthenaItemWrap": 600,
2024-01-21 00:46:06 +00:00
},
"EFortRarity::Uncommon": {
2024-01-21 00:46:06 +00:00
"AthenaCharacter": 800,
2024-02-18 00:09:02 +00:00
"AthenaBackpack": 200,
"AthenaPickaxe": 500,
"AthenaGlider": 500,
"AthenaDance": 200,
"AthenaItemWrap": 300,
2024-01-21 00:46:06 +00:00
},
"EFortRarity::Common": {
2024-01-21 00:46:06 +00:00
"AthenaCharacter": 500,
2024-02-18 00:09:02 +00:00
"AthenaBackpack": 200,
"AthenaPickaxe": 500,
"AthenaGlider": 500,
"AthenaDance": 200,
"AthenaItemWrap": 300,
2024-01-21 00:46:06 +00:00
},
}
2023-11-21 23:42:39 +00:00
2024-02-18 03:19:36 +00:00
dailyItemLookup = []struct {
Season int
Items int
}{
{2, 4},
{4, 6},
{13, 10},
2023-11-21 23:42:39 +00:00
}
2024-02-18 03:19:36 +00:00
weeklySetLookup = []struct {
Season int
Sets int
}{
{2, 2},
{4, 3},
{11, 4},
{13, 3},
2023-11-21 23:42:39 +00:00
}
2024-02-18 00:09:02 +00:00
)
2023-11-21 23:42:39 +00:00
2024-02-18 00:09:02 +00:00
func price(rarity, type_ string) int {
return priceLookup[rarity][type_]
2023-12-03 15:10:37 +00:00
}
2023-11-21 23:42:39 +00:00
2024-02-18 00:09:02 +00:00
func dailyItems(season int) int {
2024-02-18 03:19:36 +00:00
currentValue := 4
2023-11-21 23:42:39 +00:00
2024-02-18 03:19:36 +00:00
for _, item := range dailyItemLookup {
if item.Season > season {
continue
}
2024-02-18 03:19:36 +00:00
currentValue = item.Items
}
2024-02-18 03:19:36 +00:00
return currentValue
}
2024-02-18 00:09:02 +00:00
func weeklySets(season int) int {
2024-02-18 03:19:36 +00:00
currentValue := 2
2023-11-21 23:42:39 +00:00
2024-02-18 03:19:36 +00:00
for _, set := range weeklySetLookup {
if set.Season > season {
continue
2024-02-18 00:09:02 +00:00
}
2024-02-18 03:19:36 +00:00
currentValue = set.Sets
2023-11-21 23:42:39 +00:00
}
2024-02-18 03:19:36 +00:00
return currentValue
2023-11-21 23:42:39 +00:00
}
2024-02-18 00:09:02 +00:00
type FortniteCatalogSectionOffer struct {
ID string
Grants []*FortniteItem
TotalPrice int
Meta struct {
DisplayAssetPath string
NewDisplayAssetPath string
SectionId string
TileSize string
Category string
ProfileId string
2023-11-21 23:42:39 +00:00
}
2024-02-18 00:09:02 +00:00
Frontend struct {
Title string
Description string
ShortDescription string
2023-11-21 23:42:39 +00:00
}
2024-02-18 00:09:02 +00:00
Giftable bool
BundleInfo struct {
IsBundle bool
PricePercent float32
2023-11-21 23:42:39 +00:00
}
}
2024-02-18 00:09:02 +00:00
func NewFortniteCatalogSectionOffer() *FortniteCatalogSectionOffer {
return &FortniteCatalogSectionOffer{}
2023-11-21 23:42:39 +00:00
}
2024-02-18 00:09:02 +00:00
func (f *FortniteCatalogSectionOffer) GenerateID() {
for _, item := range f.Grants {
f.ID += item.Type.BackendValue + ":" + item.ID + ","
}
2024-02-18 00:09:02 +00:00
f.ID = "v2:/" + aid.Hash([]byte(f.ID))
}
2024-02-18 00:09:02 +00:00
func (f *FortniteCatalogSectionOffer) GenerateTotalPrice() {
if !f.BundleInfo.IsBundle {
f.TotalPrice = price(f.Grants[0].Rarity.BackendValue, f.Grants[0].Type.BackendValue)
return
}
2023-11-21 23:42:39 +00:00
2024-02-18 00:09:02 +00:00
for _, item := range f.Grants {
f.TotalPrice += price(item.Rarity.BackendValue, item.Rarity.BackendValue)
}
}
2024-02-18 00:09:02 +00:00
func (f *FortniteCatalogSectionOffer) GenerateFortniteCatalogSectionOffer() aid.JSON {
f.GenerateTotalPrice()
2023-11-21 23:42:39 +00:00
2024-02-18 00:09:02 +00:00
itemGrantResponse := []aid.JSON{}
purchaseRequirementsResponse := []aid.JSON{}
2024-02-18 00:09:02 +00:00
for _, item := range f.Grants {
itemGrantResponse = append(itemGrantResponse, aid.JSON{
"templateId": item.Type.BackendValue + ":" + item.ID,
"quantity": 1,
})
2024-02-18 00:09:02 +00:00
purchaseRequirementsResponse = append(purchaseRequirementsResponse, aid.JSON{
"requirementType": "DenyOnItemOwnership",
"requiredId": item.Type.BackendValue + ":" + item.ID,
"minQuantity": 1,
})
}
2024-02-18 00:09:02 +00:00
return aid.JSON{
"devName": uuid.New().String(),
"offerId": f.ID,
"offerType": "StaticPrice",
2024-02-18 00:09:02 +00:00
"prices": []aid.JSON{{
"currencyType": "MtxCurrency",
"currencySubType": "",
"regularPrice": f.TotalPrice,
"dynamicRegularPrice": f.TotalPrice,
"finalPrice": f.TotalPrice,
"basePrice": f.TotalPrice,
"saleExpiration": "9999-12-31T23:59:59.999Z",
}},
"itemGrants": itemGrantResponse,
"meta": aid.JSON{
"TileSize": f.Meta.TileSize,
"SectionId": f.Meta.SectionId,
"NewDisplayAssetPath": f.Meta.NewDisplayAssetPath,
"DisplayAssetPath": f.Meta.DisplayAssetPath,
},
"metaInfo": []aid.JSON{
{
"Key": "TileSize",
"Value": f.Meta.TileSize,
},
{
"Key": "SectionId",
"Value": f.Meta.SectionId,
},
{
"Key": "NewDisplayAssetPath",
"Value": f.Meta.NewDisplayAssetPath,
},
2023-11-21 23:42:39 +00:00
{
2024-02-18 00:09:02 +00:00
"Key": "DisplayAssetPath",
"Value": f.Meta.DisplayAssetPath,
2023-11-21 23:42:39 +00:00
},
},
2024-02-18 00:09:02 +00:00
"giftInfo": aid.JSON{
"bIsEnabled": f.Giftable,
"forcedGiftBoxTemplateId": "",
"purchaseRequirements": purchaseRequirementsResponse,
"giftRecordIds": []string{},
},
"purchaseRequirements": purchaseRequirementsResponse,
"categories": []string{f.Meta.Category},
"title": f.Frontend.Title,
"description": f.Frontend.Description,
"shortDescription": f.Frontend.ShortDescription,
"displayAssetPath": f.Meta.DisplayAssetPath,
"appStoreId": []string{},
"fufillmentIds": []string{},
2023-11-21 23:42:39 +00:00
"dailyLimit": -1,
"weeklyLimit": -1,
"monthlyLimit": -1,
2024-02-18 00:09:02 +00:00
"sortPriority": 0,
"catalogGroupPriority": 0,
"filterWeight": 0,
"refundable": true,
}
2024-02-18 00:09:02 +00:00
}
2023-11-21 23:42:39 +00:00
2024-02-18 00:09:02 +00:00
type FortniteCatalogSection struct {
Name string
Offers []*FortniteCatalogSectionOffer
}
2023-11-21 23:42:39 +00:00
2024-02-18 00:09:02 +00:00
func NewFortniteCatalogSection(name string) *FortniteCatalogSection {
return &FortniteCatalogSection{
Name: name,
2023-11-21 23:42:39 +00:00
}
2024-02-18 00:09:02 +00:00
}
2023-11-21 23:42:39 +00:00
2024-02-18 00:09:02 +00:00
func (f *FortniteCatalogSection) GenerateFortniteCatalogSection() aid.JSON {
catalogEntiresResponse := []aid.JSON{}
for _, offer := range f.Offers {
catalogEntiresResponse = append(catalogEntiresResponse, offer.GenerateFortniteCatalogSectionOffer())
2023-11-21 23:42:39 +00:00
}
2024-02-18 00:09:02 +00:00
return aid.JSON{
"name": f.Name,
"catalogEntries": catalogEntiresResponse,
2024-01-31 21:40:47 +00:00
}
}
2024-02-18 00:09:02 +00:00
func (f *FortniteCatalogSection) GetGroupedOffers() map[string][]*FortniteCatalogSectionOffer {
groupedOffers := map[string][]*FortniteCatalogSectionOffer{}
2024-02-18 00:09:02 +00:00
for _, offer := range f.Offers {
if groupedOffers[offer.Meta.Category] == nil {
groupedOffers[offer.Meta.Category] = []*FortniteCatalogSectionOffer{}
}
2024-02-18 00:09:02 +00:00
groupedOffers[offer.Meta.Category] = append(groupedOffers[offer.Meta.Category], offer)
}
2024-02-18 00:09:02 +00:00
return groupedOffers
}
2024-02-18 00:09:02 +00:00
type FortniteCatalog struct {
Sections []*FortniteCatalogSection
}
2024-02-18 00:09:02 +00:00
func NewFortniteCatalog() *FortniteCatalog {
return &FortniteCatalog{}
}
2023-12-03 15:10:37 +00:00
2024-02-18 00:09:02 +00:00
func (f *FortniteCatalog) GenerateFortniteCatalog() aid.JSON {
catalogSectionsResponse := []aid.JSON{}
for _, section := range f.Sections {
catalogSectionsResponse = append(catalogSectionsResponse, section.GenerateFortniteCatalogSection())
}
2024-02-18 00:09:02 +00:00
return aid.JSON{
"storefronts": catalogSectionsResponse,
"refreshIntervalHrs": 24,
"dailyPurchaseHrs": 24,
"expiration": "9999-12-31T23:59:59.999Z",
}
2024-02-18 00:09:02 +00:00
}
2024-02-18 00:09:02 +00:00
func NewRandomFortniteCatalog() *FortniteCatalog {
aid.SetRandom(rand.New(rand.NewSource(int64(aid.Config.Fortnite.ShopSeed) + aid.CurrentDayUnix())))
catalog := NewFortniteCatalog()
2023-12-09 00:21:08 +00:00
2024-02-18 00:09:02 +00:00
daily := NewFortniteCatalogSection("BRDailyStorefront")
for len(daily.Offers) < dailyItems(aid.Config.Fortnite.Season) {
entry := newEntryFromFortniteItem(GetRandomItemWithDisplayAssetOfNotType("AthenaCharacter"), false)
entry.Meta.SectionId = "Daily"
daily.Offers = append(daily.Offers, entry)
2023-12-03 15:10:37 +00:00
}
2024-02-18 00:09:02 +00:00
catalog.Sections = append(catalog.Sections, daily)
2023-12-03 15:10:37 +00:00
2024-02-18 00:09:02 +00:00
weekly := NewFortniteCatalogSection("BRWeeklyStorefront")
for len(weekly.GetGroupedOffers()) < weeklySets(aid.Config.Fortnite.Season) {
set := GetRandomSet()
for _, item := range set.Items {
2024-02-18 00:09:02 +00:00
if item.DisplayAssetPath == "" || item.DisplayAssetPath2 == "" {
continue
2023-12-03 15:10:37 +00:00
}
2024-02-18 00:09:02 +00:00
entry := newEntryFromFortniteItem(item, true)
entry.Meta.Category = set.BackendName
entry.Meta.SectionId = "Featured"
weekly.Offers = append(weekly.Offers, entry)
}
2024-02-18 00:09:02 +00:00
}
catalog.Sections = append(catalog.Sections, weekly)
2024-02-18 00:09:02 +00:00
return catalog
}
2024-02-18 00:09:02 +00:00
func newEntryFromFortniteItem(fortniteItem *FortniteItem, addAssets bool) *FortniteCatalogSectionOffer {
displayAsset := regexp.MustCompile(`[^/]+$`).FindString(fortniteItem.DisplayAssetPath)
2023-12-03 15:10:37 +00:00
2024-02-18 00:09:02 +00:00
entry := NewFortniteCatalogSectionOffer()
entry.Meta.TileSize = "Small"
if fortniteItem.Type.BackendValue == "AthenaCharacter" {
entry.Meta.TileSize = "Normal"
}
if addAssets {
entry.Meta.NewDisplayAssetPath = "/Game/Catalog/NewDisplayAssets/" + fortniteItem.DisplayAssetPath2 + "." + fortniteItem.DisplayAssetPath2
if displayAsset != "" {
entry.Meta.DisplayAssetPath = "/Game/Catalog/DisplayAssets/" + displayAsset + "." + displayAsset
}
2024-02-18 00:09:02 +00:00
}
entry.Meta.ProfileId = "athena"
entry.Giftable = true
entry.Grants = append(entry.Grants, fortniteItem)
entry.GenerateTotalPrice()
entry.GenerateID()
2024-02-18 00:09:02 +00:00
return entry
}
func GetOfferByOfferId(id string) *FortniteCatalogSectionOffer {
catalog := NewRandomFortniteCatalog()
for _, section := range catalog.Sections {
for _, offer := range section.Offers {
if offer.ID == id {
return offer
}
}
}
2024-02-18 00:09:02 +00:00
return nil
2023-11-21 23:42:39 +00:00
}