Finish Loadouts on newer seasons; Add every item in the game.

This commit is contained in:
eccentric 2023-11-20 23:20:42 +00:00
parent 5508ad4348
commit f1d99b23c7
9 changed files with 226 additions and 53 deletions

View File

@ -27,6 +27,7 @@ type CS struct {
Fortnite struct { Fortnite struct {
Season int Season int
Build float64 Build float64
Everything bool
} }
} }
@ -104,4 +105,5 @@ func LoadConfig() {
} }
Config.Fortnite.Season = parsedSeason Config.Fortnite.Season = parsedSeason
Config.Fortnite.Everything = cfg.Section("fortnite").Key("everything").MustBool(false)
} }

View File

@ -26,4 +26,6 @@ secret="secret"
[fortnite] [fortnite]
; used for account creation + lobby ; used for account creation + lobby
build=5.41 build=5.41
; own every cosmetic in the game. this applies to all accounts
everything=true

View File

@ -17,8 +17,11 @@ var (
"QueryProfile": PostQueryProfileAction, "QueryProfile": PostQueryProfileAction,
"ClientQuestLogin": PostQueryProfileAction, "ClientQuestLogin": PostQueryProfileAction,
"MarkItemSeen": PostMarkItemSeenAction, "MarkItemSeen": PostMarkItemSeenAction,
"SetItemFavoriteStatusBatch": PostSetItemFavoriteStatusBatchAction,
"EquipBattleRoyaleCustomization": PostEquipBattleRoyaleCustomizationAction, "EquipBattleRoyaleCustomization": PostEquipBattleRoyaleCustomizationAction,
"SetBattleRoyaleBanner": PostSetBattleRoyaleBannerAction, "SetBattleRoyaleBanner": PostSetBattleRoyaleBannerAction,
"SetCosmeticLockerSlot": PostSetCosmeticLockerSlotAction,
"SetCosmeticLockerBanner": PostSetCosmeticLockerBannerAction,
} }
) )
@ -177,4 +180,134 @@ func PostSetBattleRoyaleBannerAction(c *fiber.Ctx, person *p.Person, profile *p.
colorAttr.Save() colorAttr.Save()
}() }()
return nil return nil
}
func PostSetItemFavoriteStatusBatchAction(c *fiber.Ctx, person *p.Person, profile *p.Profile) error {
var body struct {
ItemIds []string `json:"itemIds" binding:"required"`
Favorite []bool `json:"itemFavStatus" binding:"required"`
}
err := c.BodyParser(&body)
if err != nil {
return fmt.Errorf("invalid Body")
}
for i, itemId := range body.ItemIds {
item := profile.Items.GetItem(itemId)
if item == nil {
continue
}
item.Favorite = body.Favorite[i]
go item.Save()
}
return nil
}
func PostSetCosmeticLockerSlotAction(c *fiber.Ctx, person *p.Person, profile *p.Profile) error {
var body struct {
Category string `json:"category" binding:"required"` // item type e.g. Character
ItemToSlot string `json:"itemToSlot" binding:"required"` // template id
LockerItem string `json:"lockerItem" binding:"required"` // locker id
SlotIndex int `json:"slotIndex" binding:"required"` // index of slot
VariantUpdates []aid.JSON `json:"variantUpdates" binding:"required"` // variant updates
}
err := c.BodyParser(&body)
if err != nil {
return fmt.Errorf("invalid Body")
}
item := profile.Items.GetItemByTemplateID(body.ItemToSlot)
if item == nil {
if body.ItemToSlot != "" && !strings.Contains(strings.ToLower(body.ItemToSlot), "random") {
return fmt.Errorf("item not found")
}
item = &p.Item{
ID: body.ItemToSlot,
}
}
currentLocker := profile.Loadouts.GetLoadout(body.LockerItem)
if currentLocker == nil {
return fmt.Errorf("current locker not found")
}
switch body.Category {
case "Character":
currentLocker.CharacterID = item.ID
case "Backpack":
currentLocker.BackpackID = item.ID
case "Pickaxe":
currentLocker.PickaxeID = item.ID
case "Glider":
currentLocker.GliderID = item.ID
case "ItemWrap":
if body.SlotIndex == -1 {
for i := range currentLocker.ItemWrapID {
currentLocker.ItemWrapID[i] = item.ID
}
break
}
currentLocker.ItemWrapID[body.SlotIndex] = item.ID
profile.CreateLoadoutChangedChange(currentLocker, "ItemWrapID")
case "Dance":
if body.SlotIndex == -1 {
for i := range currentLocker.DanceID {
currentLocker.DanceID[i] = item.ID
}
break
}
currentLocker.DanceID[body.SlotIndex] = item.ID
profile.CreateLoadoutChangedChange(currentLocker, "DanceID")
case "SkyDiveContrail":
currentLocker.ContrailID = item.ID
case "LoadingScreen":
currentLocker.LoadingScreenID = item.ID
case "MusicPack":
currentLocker.MusicPackID = item.ID
}
go currentLocker.Save()
return nil
}
func PostSetCosmeticLockerBannerAction(c *fiber.Ctx, person *p.Person, profile *p.Profile) error {
var body struct {
LockerItem string `json:"lockerItem" binding:"required"` // locker id
BannerColorTemplateName string `json:"bannerColorTemplateName" binding:"required"` // template id
BannerIconTemplateName string `json:"bannerIconTemplateName" binding:"required"` // template id
}
err := c.BodyParser(&body)
if err != nil {
return fmt.Errorf("invalid Body")
}
color := person.CommonCoreProfile.Items.GetItemByTemplateID("HomebaseBannerColor:" + body.BannerColorTemplateName)
if color == nil {
return fmt.Errorf("color item not found")
}
icon := profile.Items.GetItemByTemplateID("HomebaseBannerIcon:" + body.BannerIconTemplateName)
if icon == nil {
// return fmt.Errorf("icon item not found")
icon = &p.Item{
ID: body.BannerIconTemplateName,
}
}
currentLocker := profile.Loadouts.GetLoadout(body.LockerItem)
if currentLocker == nil {
return fmt.Errorf("current locker not found")
}
currentLocker.BannerColorID = color.ID
currentLocker.BannerID = icon.ID
go currentLocker.Save()
return nil
} }

View File

@ -47,7 +47,7 @@ func main() {
r.Get("/content/api/pages/fortnite-game", handlers.GetContentPages) r.Get("/content/api/pages/fortnite-game", handlers.GetContentPages)
r.Get("/waitingroom/api/waitingroom", handlers.GetWaitingRoomStatus) r.Get("/waitingroom/api/waitingroom", handlers.GetWaitingRoomStatus)
r.Get("/region", handlers.GetRegion) r.Get("/region", handlers.GetRegion)
r.Put("/profile/play_region", handlers.AnyNoContent) // r.Put("/profile/play_region", handlers.AnyNoContent)
r.Get("/snow/cache", func(c *fiber.Ctx) error { r.Get("/snow/cache", func(c *fiber.Ctx) error {
cache := person.AllFromCache() cache := person.AllFromCache()

View File

@ -67,8 +67,6 @@ func NewFortnitePerson(displayName string, key string) *Person {
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_update", 0)).Save() person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_update", 0)).Save()
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_num", aid.Config.Fortnite.Season)).Save() person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_num", aid.Config.Fortnite.Season)).Save()
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("permissions", []aid.JSON{})).Save() person.AthenaProfile.Attributes.AddAttribute(NewAttribute("permissions", []aid.JSON{})).Save()
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("last_applied_loadout", "")).Save()
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("active_loadout_index", 0)).Save()
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("accountLevel", 1)).Save() person.AthenaProfile.Attributes.AddAttribute(NewAttribute("accountLevel", 1)).Save()
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("level", 1)).Save() person.AthenaProfile.Attributes.AddAttribute(NewAttribute("level", 1)).Save()
@ -114,12 +112,14 @@ func NewFortnitePerson(displayName string, key string) *Person {
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("last_applied_loadout", loadout.ID)).Save() person.AthenaProfile.Attributes.AddAttribute(NewAttribute("last_applied_loadout", loadout.ID)).Save()
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("active_loadout_index", 0)).Save() person.AthenaProfile.Attributes.AddAttribute(NewAttribute("active_loadout_index", 0)).Save()
allItemsBytes := storage.Asset("cosmetics.json") if aid.Config.Fortnite.Everything {
var allItems []string allItemsBytes := storage.Asset("cosmetics.json")
json.Unmarshal(*allItemsBytes, &allItems) var allItems []string
json.Unmarshal(*allItemsBytes, &allItems)
for _, item := range allItems {
person.AthenaProfile.Items.AddItem(NewItem(item, 1)).Save() for _, item := range allItems {
person.AthenaProfile.Items.AddItem(NewItem(item, 1)).Save()
}
} }
person.Save() person.Save()

View File

@ -8,6 +8,7 @@ import (
type Loadout struct { type Loadout struct {
ID string ID string
PersonID string
ProfileID string ProfileID string
TemplateID string TemplateID string
LockerName string LockerName string
@ -65,7 +66,7 @@ func NewLoadout(name string, athena *Profile) *Loadout {
return &Loadout{ return &Loadout{
ID: uuid.New().String(), ID: uuid.New().String(),
ProfileID: athena.ID, PersonID: athena.ID,
TemplateID: "CosmeticLocker:CosmeticLocker_Athena", TemplateID: "CosmeticLocker:CosmeticLocker_Athena",
LockerName: name, LockerName: name,
CharacterID: aid.JSONParse(character.ValueJSON).(string), CharacterID: aid.JSONParse(character.ValueJSON).(string),
@ -103,12 +104,26 @@ func FromDatabaseLoadout(loadout *storage.DB_Loadout) *Loadout {
} }
func (l *Loadout) GenerateFortniteLoadoutEntry() aid.JSON { func (l *Loadout) GenerateFortniteLoadoutEntry() aid.JSON {
bannerItem := Find(l.PersonID).AthenaProfile.Items.GetItem(l.BannerID)
if bannerItem == nil {
bannerItem = &Item{
TemplateID: "HomebaseBannerIcon:StandardBanner1",
}
}
bannerColorItem := Find(l.PersonID).AthenaProfile.Items.GetItem(l.BannerColorID)
if bannerColorItem == nil {
bannerColorItem = &Item{
TemplateID: "HomebaseBannerColor:DefaultColor1",
}
}
json := aid.JSON{ json := aid.JSON{
"templateId": l.TemplateID, "templateId": l.TemplateID,
"attributes": aid.JSON{ "attributes": aid.JSON{
"locker_name": l.LockerName, "locker_name": l.LockerName,
"banner_icon_template": l.BannerID, "banner_icon_template": bannerItem.TemplateID,
"banner_color_template": l.BannerColorID, "banner_color_template": bannerColorItem.TemplateID,
"locker_slots_data": l.GenerateFortniteLockerSlotsData(), "locker_slots_data": l.GenerateFortniteLockerSlotsData(),
"item_seen": true, "item_seen": true,
}, },
@ -118,13 +133,27 @@ func (l *Loadout) GenerateFortniteLoadoutEntry() aid.JSON {
} }
func (l *Loadout) GetAttribute(attribute string) interface{} { func (l *Loadout) GetAttribute(attribute string) interface{} {
bannerItem := Find(l.PersonID).AthenaProfile.Items.GetItem(l.BannerID)
if bannerItem == nil {
bannerItem = &Item{
TemplateID: "HomebaseBannerIcon:StandardBanner1",
}
}
bannerColorItem := Find(l.PersonID).AthenaProfile.Items.GetItem(l.BannerColorID)
if bannerColorItem == nil {
bannerColorItem = &Item{
TemplateID: "HomebaseBannerColor:DefaultColor5",
}
}
switch attribute { switch attribute {
case "locker_name": case "locker_name":
return l.LockerName return l.LockerName
case "banner_icon_template": case "banner_icon_template":
return l.BannerID return bannerItem.TemplateID
case "banner_color_template": case "banner_color_template":
return l.BannerColorID return bannerColorItem.TemplateID
case "locker_slots_data": case "locker_slots_data":
return l.GenerateFortniteLockerSlotsData() return l.GenerateFortniteLockerSlotsData()
} }
@ -154,7 +183,7 @@ func (l *Loadout) GetItemSlotData(itemId string) aid.JSON {
"activeVariants": []aid.JSON{}, "activeVariants": []aid.JSON{},
} }
person := Find(l.ProfileID) person := Find(l.PersonID)
if person == nil { if person == nil {
return json return json
} }
@ -179,40 +208,38 @@ func (l *Loadout) GetItemSlotData(itemId string) aid.JSON {
func (l *Loadout) GetItemsSlotData(itemIds []string) aid.JSON { func (l *Loadout) GetItemsSlotData(itemIds []string) aid.JSON {
json := aid.JSON{ json := aid.JSON{
"items": []string{}, "items": make([]string, len(itemIds)),
"activeVariants": []aid.JSON{}, "activeVariants": make([]aid.JSON, len(itemIds)),
} }
person := Find(l.ProfileID) person := Find(l.PersonID)
if person == nil { if person == nil {
return json return json
} }
for _, itemId := range itemIds { for idx, itemId := range itemIds {
item := person.AthenaProfile.Items.GetItem(itemId) item := person.AthenaProfile.Items.GetItem(itemId)
if item == nil { if item == nil {
item = &Item{ item = &Item{
ProfileID: l.ProfileID, TemplateID: "",
Variants: []*VariantChannel{}, Variants: []*VariantChannel{},
} }
} }
items := json["items"].([]string) items := json["items"].([]string)
items = append(items, item.TemplateID) items[idx] = item.TemplateID
activeVariants := json["activeVariants"].([]aid.JSON) activeVariants := json["activeVariants"].([]aid.JSON)
activeVariants = append(activeVariants, aid.JSON{ activeVariants[idx] = aid.JSON{
"variants": item.GenerateFortniteItemVariantChannels(), "variants": []aid.JSON{},
}) }
json["items"] = items json["items"] = items
json["activeVariants"] = activeVariants json["activeVariants"] = activeVariants
} }
return aid.JSON{ return json
"items": itemIds,
"activeVariants": []aid.JSON{},
}
} }
func (l *Loadout) Delete() { func (l *Loadout) Delete() {

View File

@ -183,6 +183,8 @@ func (p *Profile) Diff(b *ProfileSnapshot) []diff.Change {
return nil return nil
} }
aid.PrintJSON(changes)
for _, change := range changes { for _, change := range changes {
switch change.Path[0] { switch change.Path[0] {
case "Items": case "Items":
@ -333,20 +335,13 @@ func (p *Profile) CreateItemAttributeChangedChange(item *Item, attribute string)
} }
p.Changes = append(p.Changes, ItemAttributeChanged{ p.Changes = append(p.Changes, ItemAttributeChanged{
ChangeType: "itemAttributeChanged", ChangeType: "itemAttrChanged",
ItemId: item.ID, ItemId: item.ID,
AttributeName: lookup[attribute], AttributeName: lookup[attribute],
AttributeValue: item.GetAttribute(attribute), AttributeValue: item.GetAttribute(attribute),
}) })
} }
func (p *Profile) CreateFullProfileUpdateChange() {
p.Changes = []interface{}{FullProfileUpdate{
ChangeType: "fullProfileUpdate",
Profile: p.GenerateFortniteProfileEntry(),
}}
}
func (p *Profile) CreateLoadoutAddedChange(loadout *Loadout) { func (p *Profile) CreateLoadoutAddedChange(loadout *Loadout) {
if loadout == nil { if loadout == nil {
fmt.Println("error getting item from profile", loadout.ID) fmt.Println("error getting item from profile", loadout.ID)
@ -389,13 +384,20 @@ func (p *Profile) CreateLoadoutChangedChange(loadout *Loadout, attribute string)
} }
p.Changes = append(p.Changes, ItemAttributeChanged{ p.Changes = append(p.Changes, ItemAttributeChanged{
ChangeType: "itemAttributeChanged", ChangeType: "itemAttrChanged",
ItemId: loadout.ID, ItemId: loadout.ID,
AttributeName: lookup[attribute], AttributeName: lookup[attribute],
AttributeValue: loadout.GetAttribute(lookup[attribute]), AttributeValue: loadout.GetAttribute(lookup[attribute]),
}) })
} }
func (p *Profile) CreateFullProfileUpdateChange() {
p.Changes = []interface{}{FullProfileUpdate{
ChangeType: "fullProfileUpdate",
Profile: p.GenerateFortniteProfileEntry(),
}}
}
func (p *Profile) ClearProfileChanges() { func (p *Profile) ClearProfileChanges() {
p.Changes = []interface{}{} p.Changes = []interface{}{}
} }

View File

@ -240,17 +240,19 @@ func (m *AttributeMutex) Count() int {
type LoadoutMutex struct { type LoadoutMutex struct {
sync.Map sync.Map
ProfileType string PersonID string
ProfileID string ProfileID string
} }
func NewLoadoutMutex(profile *storage.DB_Profile) *LoadoutMutex { func NewLoadoutMutex(profile *storage.DB_Profile) *LoadoutMutex {
return &LoadoutMutex{ return &LoadoutMutex{
ProfileID: profile.ID, PersonID: profile.PersonID,
ProfileID: profile.ID,
} }
} }
func (m *LoadoutMutex) AddLoadout(loadout *Loadout) *Loadout { func (m *LoadoutMutex) AddLoadout(loadout *Loadout) *Loadout {
loadout.PersonID = m.PersonID
loadout.ProfileID = m.ProfileID loadout.ProfileID = m.ProfileID
m.Store(loadout.ID, loadout) m.Store(loadout.ID, loadout)
// storage.Repo.SaveLoadout(loadout.ToDatabase(m.ProfileID)) // storage.Repo.SaveLoadout(loadout.ToDatabase(m.ProfileID))

View File

@ -12,8 +12,13 @@ type PostgresStorage struct {
} }
func NewPostgresStorage() *PostgresStorage { func NewPostgresStorage() *PostgresStorage {
l := logger.Default.LogMode(logger.Silent)
if aid.Config.Output.Level == "time" {
l = logger.Default.LogMode(logger.Info)
}
db, err := gorm.Open(postgres.Open(aid.Config.Database.URI), &gorm.Config{ db, err := gorm.Open(postgres.Open(aid.Config.Database.URI), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info), Logger: l,
}) })
if err != nil { if err != nil {
panic(err) panic(err)
@ -34,10 +39,10 @@ func (s *PostgresStorage) MigrateAll() {
s.Migrate(&DB_Item{}, "Items") s.Migrate(&DB_Item{}, "Items")
s.Migrate(&DB_Gift{}, "Gifts") s.Migrate(&DB_Gift{}, "Gifts")
s.Migrate(&DB_Quest{}, "Quests") s.Migrate(&DB_Quest{}, "Quests")
s.Migrate(&DB_Loadout{}, "Loadouts")
s.Migrate(&DB_Loot{}, "Loot") s.Migrate(&DB_Loot{}, "Loot")
s.Migrate(&DB_VariantChannel{}, "Variants") s.Migrate(&DB_VariantChannel{}, "Variants")
s.Migrate(&DB_PAttribute{}, "Attributes") s.Migrate(&DB_PAttribute{}, "Attributes")
s.Migrate(&DB_Loadout{}, "Loadouts")
} }
func (s *PostgresStorage) DropTables() { func (s *PostgresStorage) DropTables() {
@ -48,13 +53,13 @@ func (s *PostgresStorage) GetPerson(personId string) *DB_Person {
var dbPerson DB_Person var dbPerson DB_Person
s.Postgres. s.Postgres.
Preload("Profiles"). Preload("Profiles").
Preload("Profiles.Loadouts").
Preload("Profiles.Items.Variants"). Preload("Profiles.Items.Variants").
Preload("Profiles.Gifts.Loot"). Preload("Profiles.Gifts.Loot").
Preload("Profiles.Attributes"). Preload("Profiles.Attributes").
Preload("Profiles.Items"). Preload("Profiles.Items").
Preload("Profiles.Gifts"). Preload("Profiles.Gifts").
Preload("Profiles.Quests"). Preload("Profiles.Quests").
Preload("Profiles.Loadouts").
Where("id = ?", personId). Where("id = ?", personId).
Find(&dbPerson) Find(&dbPerson)
@ -68,14 +73,14 @@ func (s *PostgresStorage) GetPerson(personId string) *DB_Person {
func (s *PostgresStorage) GetPersonByDisplay(displayName string) *DB_Person { func (s *PostgresStorage) GetPersonByDisplay(displayName string) *DB_Person {
var dbPerson DB_Person var dbPerson DB_Person
s.Postgres. s.Postgres.
// Preload("Profiles"). Preload("Profiles").
// Preload("Profiles.Items.Variants"). Preload("Profiles.Loadouts").
// Preload("Profiles.Gifts.Loot"). Preload("Profiles.Items.Variants").
// Preload("Profiles.Attributes"). Preload("Profiles.Gifts.Loot").
// Preload("Profiles.Items"). Preload("Profiles.Attributes").
// Preload("Profiles.Gifts"). Preload("Profiles.Items").
// Preload("Profiles.Quests"). Preload("Profiles.Gifts").
// Preload("Profiles.Loadouts"). Preload("Profiles.Quests").
Where("display_name = ?", displayName). Where("display_name = ?", displayName).
Find(&dbPerson) Find(&dbPerson)
@ -91,13 +96,13 @@ func (s *PostgresStorage) GetAllPersons() []*DB_Person {
s.Postgres. s.Postgres.
Preload("Profiles"). Preload("Profiles").
Preload("Profiles.Loadouts").
Preload("Profiles.Items.Variants"). Preload("Profiles.Items.Variants").
Preload("Profiles.Gifts.Loot"). Preload("Profiles.Gifts.Loot").
Preload("Profiles.Attributes"). Preload("Profiles.Attributes").
Preload("Profiles.Items"). Preload("Profiles.Items").
Preload("Profiles.Gifts"). Preload("Profiles.Gifts").
Preload("Profiles.Quests"). Preload("Profiles.Quests").
Preload("Profiles.Loadouts").
Find(&dbPersons) Find(&dbPersons)
return dbPersons return dbPersons