From f1d99b23c7285edcddd6b99b97f7567a230f53a5 Mon Sep 17 00:00:00 2001 From: eccentric Date: Mon, 20 Nov 2023 23:20:42 +0000 Subject: [PATCH] Finish Loadouts on newer seasons; Add every item in the game. --- aid/config.go | 2 + default.config.ini | 4 +- handlers/profile.go | 133 ++++++++++++++++++++++++++++++++++++++++++++ main.go | 2 +- person/fortnite.go | 16 +++--- person/loadout.go | 67 +++++++++++++++------- person/profile.go | 20 ++++--- person/sync.go | 6 +- storage/postgres.go | 29 ++++++---- 9 files changed, 226 insertions(+), 53 deletions(-) diff --git a/aid/config.go b/aid/config.go index 7de6efb..427ffc9 100644 --- a/aid/config.go +++ b/aid/config.go @@ -27,6 +27,7 @@ type CS struct { Fortnite struct { Season int Build float64 + Everything bool } } @@ -104,4 +105,5 @@ func LoadConfig() { } Config.Fortnite.Season = parsedSeason + Config.Fortnite.Everything = cfg.Section("fortnite").Key("everything").MustBool(false) } \ No newline at end of file diff --git a/default.config.ini b/default.config.ini index da279e6..df2b098 100644 --- a/default.config.ini +++ b/default.config.ini @@ -26,4 +26,6 @@ secret="secret" [fortnite] ; used for account creation + lobby -build=5.41 \ No newline at end of file +build=5.41 +; own every cosmetic in the game. this applies to all accounts +everything=true \ No newline at end of file diff --git a/handlers/profile.go b/handlers/profile.go index 0d0bd45..e4343ec 100644 --- a/handlers/profile.go +++ b/handlers/profile.go @@ -17,8 +17,11 @@ var ( "QueryProfile": PostQueryProfileAction, "ClientQuestLogin": PostQueryProfileAction, "MarkItemSeen": PostMarkItemSeenAction, + "SetItemFavoriteStatusBatch": PostSetItemFavoriteStatusBatchAction, "EquipBattleRoyaleCustomization": PostEquipBattleRoyaleCustomizationAction, "SetBattleRoyaleBanner": PostSetBattleRoyaleBannerAction, + "SetCosmeticLockerSlot": PostSetCosmeticLockerSlotAction, + "SetCosmeticLockerBanner": PostSetCosmeticLockerBannerAction, } ) @@ -177,4 +180,134 @@ func PostSetBattleRoyaleBannerAction(c *fiber.Ctx, person *p.Person, profile *p. colorAttr.Save() }() 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 } \ No newline at end of file diff --git a/main.go b/main.go index cf3ca49..11589aa 100644 --- a/main.go +++ b/main.go @@ -47,7 +47,7 @@ func main() { r.Get("/content/api/pages/fortnite-game", handlers.GetContentPages) r.Get("/waitingroom/api/waitingroom", handlers.GetWaitingRoomStatus) 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 { cache := person.AllFromCache() diff --git a/person/fortnite.go b/person/fortnite.go index 1c1f894..cec9bd5 100644 --- a/person/fortnite.go +++ b/person/fortnite.go @@ -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_num", aid.Config.Fortnite.Season)).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("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("active_loadout_index", 0)).Save() - allItemsBytes := storage.Asset("cosmetics.json") - var allItems []string - json.Unmarshal(*allItemsBytes, &allItems) - - for _, item := range allItems { - person.AthenaProfile.Items.AddItem(NewItem(item, 1)).Save() + if aid.Config.Fortnite.Everything { + allItemsBytes := storage.Asset("cosmetics.json") + var allItems []string + json.Unmarshal(*allItemsBytes, &allItems) + + for _, item := range allItems { + person.AthenaProfile.Items.AddItem(NewItem(item, 1)).Save() + } } person.Save() diff --git a/person/loadout.go b/person/loadout.go index 955cf58..17a6c5c 100644 --- a/person/loadout.go +++ b/person/loadout.go @@ -8,6 +8,7 @@ import ( type Loadout struct { ID string + PersonID string ProfileID string TemplateID string LockerName string @@ -65,7 +66,7 @@ func NewLoadout(name string, athena *Profile) *Loadout { return &Loadout{ ID: uuid.New().String(), - ProfileID: athena.ID, + PersonID: athena.ID, TemplateID: "CosmeticLocker:CosmeticLocker_Athena", LockerName: name, CharacterID: aid.JSONParse(character.ValueJSON).(string), @@ -103,12 +104,26 @@ func FromDatabaseLoadout(loadout *storage.DB_Loadout) *Loadout { } 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{ "templateId": l.TemplateID, "attributes": aid.JSON{ "locker_name": l.LockerName, - "banner_icon_template": l.BannerID, - "banner_color_template": l.BannerColorID, + "banner_icon_template": bannerItem.TemplateID, + "banner_color_template": bannerColorItem.TemplateID, "locker_slots_data": l.GenerateFortniteLockerSlotsData(), "item_seen": true, }, @@ -118,13 +133,27 @@ func (l *Loadout) GenerateFortniteLoadoutEntry() aid.JSON { } 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 { case "locker_name": return l.LockerName case "banner_icon_template": - return l.BannerID + return bannerItem.TemplateID case "banner_color_template": - return l.BannerColorID + return bannerColorItem.TemplateID case "locker_slots_data": return l.GenerateFortniteLockerSlotsData() } @@ -154,7 +183,7 @@ func (l *Loadout) GetItemSlotData(itemId string) aid.JSON { "activeVariants": []aid.JSON{}, } - person := Find(l.ProfileID) + person := Find(l.PersonID) if person == nil { return json } @@ -179,40 +208,38 @@ func (l *Loadout) GetItemSlotData(itemId string) aid.JSON { func (l *Loadout) GetItemsSlotData(itemIds []string) aid.JSON { json := aid.JSON{ - "items": []string{}, - "activeVariants": []aid.JSON{}, + "items": make([]string, len(itemIds)), + "activeVariants": make([]aid.JSON, len(itemIds)), } - person := Find(l.ProfileID) + person := Find(l.PersonID) if person == nil { return json } - for _, itemId := range itemIds { + for idx, itemId := range itemIds { item := person.AthenaProfile.Items.GetItem(itemId) if item == nil { item = &Item{ - ProfileID: l.ProfileID, + TemplateID: "", Variants: []*VariantChannel{}, } } - + items := json["items"].([]string) - items = append(items, item.TemplateID) + items[idx] = item.TemplateID + activeVariants := json["activeVariants"].([]aid.JSON) - activeVariants = append(activeVariants, aid.JSON{ - "variants": item.GenerateFortniteItemVariantChannels(), - }) + activeVariants[idx] = aid.JSON{ + "variants": []aid.JSON{}, + } json["items"] = items json["activeVariants"] = activeVariants } - return aid.JSON{ - "items": itemIds, - "activeVariants": []aid.JSON{}, - } + return json } func (l *Loadout) Delete() { diff --git a/person/profile.go b/person/profile.go index da721ce..564ed83 100644 --- a/person/profile.go +++ b/person/profile.go @@ -183,6 +183,8 @@ func (p *Profile) Diff(b *ProfileSnapshot) []diff.Change { return nil } + aid.PrintJSON(changes) + for _, change := range changes { switch change.Path[0] { case "Items": @@ -333,20 +335,13 @@ func (p *Profile) CreateItemAttributeChangedChange(item *Item, attribute string) } p.Changes = append(p.Changes, ItemAttributeChanged{ - ChangeType: "itemAttributeChanged", + ChangeType: "itemAttrChanged", ItemId: item.ID, AttributeName: lookup[attribute], AttributeValue: item.GetAttribute(attribute), }) } -func (p *Profile) CreateFullProfileUpdateChange() { - p.Changes = []interface{}{FullProfileUpdate{ - ChangeType: "fullProfileUpdate", - Profile: p.GenerateFortniteProfileEntry(), - }} -} - func (p *Profile) CreateLoadoutAddedChange(loadout *Loadout) { if loadout == nil { 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{ - ChangeType: "itemAttributeChanged", + ChangeType: "itemAttrChanged", ItemId: loadout.ID, AttributeName: lookup[attribute], AttributeValue: loadout.GetAttribute(lookup[attribute]), }) } +func (p *Profile) CreateFullProfileUpdateChange() { + p.Changes = []interface{}{FullProfileUpdate{ + ChangeType: "fullProfileUpdate", + Profile: p.GenerateFortniteProfileEntry(), + }} +} + func (p *Profile) ClearProfileChanges() { p.Changes = []interface{}{} } \ No newline at end of file diff --git a/person/sync.go b/person/sync.go index 9267ca9..d6f073e 100644 --- a/person/sync.go +++ b/person/sync.go @@ -240,17 +240,19 @@ func (m *AttributeMutex) Count() int { type LoadoutMutex struct { sync.Map - ProfileType string + PersonID string ProfileID string } func NewLoadoutMutex(profile *storage.DB_Profile) *LoadoutMutex { return &LoadoutMutex{ - ProfileID: profile.ID, + PersonID: profile.PersonID, + ProfileID: profile.ID, } } func (m *LoadoutMutex) AddLoadout(loadout *Loadout) *Loadout { + loadout.PersonID = m.PersonID loadout.ProfileID = m.ProfileID m.Store(loadout.ID, loadout) // storage.Repo.SaveLoadout(loadout.ToDatabase(m.ProfileID)) diff --git a/storage/postgres.go b/storage/postgres.go index 6522092..97c1f5c 100644 --- a/storage/postgres.go +++ b/storage/postgres.go @@ -12,8 +12,13 @@ type PostgresStorage struct { } 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{ - Logger: logger.Default.LogMode(logger.Info), + Logger: l, }) if err != nil { panic(err) @@ -34,10 +39,10 @@ func (s *PostgresStorage) MigrateAll() { s.Migrate(&DB_Item{}, "Items") s.Migrate(&DB_Gift{}, "Gifts") s.Migrate(&DB_Quest{}, "Quests") + s.Migrate(&DB_Loadout{}, "Loadouts") s.Migrate(&DB_Loot{}, "Loot") s.Migrate(&DB_VariantChannel{}, "Variants") s.Migrate(&DB_PAttribute{}, "Attributes") - s.Migrate(&DB_Loadout{}, "Loadouts") } func (s *PostgresStorage) DropTables() { @@ -48,13 +53,13 @@ func (s *PostgresStorage) GetPerson(personId string) *DB_Person { var dbPerson DB_Person s.Postgres. Preload("Profiles"). + Preload("Profiles.Loadouts"). Preload("Profiles.Items.Variants"). Preload("Profiles.Gifts.Loot"). Preload("Profiles.Attributes"). Preload("Profiles.Items"). Preload("Profiles.Gifts"). Preload("Profiles.Quests"). - Preload("Profiles.Loadouts"). Where("id = ?", personId). Find(&dbPerson) @@ -68,14 +73,14 @@ func (s *PostgresStorage) GetPerson(personId string) *DB_Person { func (s *PostgresStorage) GetPersonByDisplay(displayName string) *DB_Person { var dbPerson DB_Person s.Postgres. - // Preload("Profiles"). - // Preload("Profiles.Items.Variants"). - // Preload("Profiles.Gifts.Loot"). - // Preload("Profiles.Attributes"). - // Preload("Profiles.Items"). - // Preload("Profiles.Gifts"). - // Preload("Profiles.Quests"). - // Preload("Profiles.Loadouts"). + Preload("Profiles"). + Preload("Profiles.Loadouts"). + Preload("Profiles.Items.Variants"). + Preload("Profiles.Gifts.Loot"). + Preload("Profiles.Attributes"). + Preload("Profiles.Items"). + Preload("Profiles.Gifts"). + Preload("Profiles.Quests"). Where("display_name = ?", displayName). Find(&dbPerson) @@ -91,13 +96,13 @@ func (s *PostgresStorage) GetAllPersons() []*DB_Person { s.Postgres. Preload("Profiles"). + Preload("Profiles.Loadouts"). Preload("Profiles.Items.Variants"). Preload("Profiles.Gifts.Loot"). Preload("Profiles.Attributes"). Preload("Profiles.Items"). Preload("Profiles.Gifts"). Preload("Profiles.Quests"). - Preload("Profiles.Loadouts"). Find(&dbPersons) return dbPersons