diff --git a/aid/syncer.go b/aid/syncer.go index cbaf56a..9b5c84c 100644 --- a/aid/syncer.go +++ b/aid/syncer.go @@ -64,4 +64,13 @@ func (s *GenericSyncMap[T]) Len() int { return true }) return count +} + +func (s *GenericSyncMap[T]) Snapshot() *map[string]*T { + m := make(map[string]*T) + s.Range(func(key string, value *T) bool { + m[key] = value + return true + }) + return &m } \ No newline at end of file diff --git a/default.config.ini b/default.config.ini index aec6b78..b402305 100644 --- a/default.config.ini +++ b/default.config.ini @@ -4,7 +4,7 @@ ; they will have max permissions with snow and will have no discord account linked gods=god,snow ; comma separated list of usernames that are considered owner accounts -; these accounts will have max permissions with snow and can have a discord account linked +; these accounts must already exist in the database owners=ectrc [database] diff --git a/discord/admin.go b/discord/admin.go index ceb3b8c..5e8ec76 100644 --- a/discord/admin.go +++ b/discord/admin.go @@ -8,13 +8,14 @@ import ( "github.com/ectrc/snow/aid" "github.com/ectrc/snow/fortnite" "github.com/ectrc/snow/person" + "github.com/ectrc/snow/socket" "github.com/ectrc/snow/storage" ) func informationHandler(s *discordgo.Session, i *discordgo.InteractionCreate) { looker := person.FindByDiscord(i.Member.User.ID) if looker == nil { - s.InteractionRespond(i.Interaction, &ErrorNoPermission) + s.InteractionRespond(i.Interaction, &ErrorNoAccount) return } @@ -46,7 +47,7 @@ func informationHandler(s *discordgo.Session, i *discordgo.InteractionCreate) { func whoHandler(s *discordgo.Session, i *discordgo.InteractionCreate) { looker := person.FindByDiscord(i.Member.User.ID) if looker == nil { - s.InteractionRespond(i.Interaction, &ErrorNoPermission) + s.InteractionRespond(i.Interaction, &ErrorNoAccount) return } @@ -111,7 +112,7 @@ func whoHandler(s *discordgo.Session, i *discordgo.InteractionCreate) { func bansHandler(s *discordgo.Session, i *discordgo.InteractionCreate) { looker := person.FindByDiscord(i.Member.User.ID) if looker == nil { - s.InteractionRespond(i.Interaction, &ErrorNoPermission) + s.InteractionRespond(i.Interaction, &ErrorNoAccount) return } @@ -216,7 +217,7 @@ func listBansHandler(s *discordgo.Session, i *discordgo.InteractionCreate, looke func itemsHandler(s *discordgo.Session, i *discordgo.InteractionCreate) { looker := person.FindByDiscord(i.Member.User.ID) if looker == nil { - s.InteractionRespond(i.Interaction, &ErrorNoPermission) + s.InteractionRespond(i.Interaction, &ErrorNoAccount) return } @@ -385,7 +386,7 @@ func fillItemsHandler(s *discordgo.Session, i *discordgo.InteractionCreate, look func permissionHandler(s *discordgo.Session, i *discordgo.InteractionCreate) { looker := person.FindByDiscord(i.Member.User.ID) if looker == nil { - s.InteractionRespond(i.Interaction, &ErrorNoPermission) + s.InteractionRespond(i.Interaction, &ErrorNoAccount) return } @@ -455,4 +456,64 @@ func permissionHandler(s *discordgo.Session, i *discordgo.InteractionCreate) { } s.InteractionRespond(i.Interaction, &ErrorInvalidArguments) +} + +func rewardHandler(s *discordgo.Session, i *discordgo.InteractionCreate) { + looker := person.FindByDiscord(i.Member.User.ID) + if looker == nil { + s.InteractionRespond(i.Interaction, &ErrorNoAccount) + return + } + + if !looker.HasPermission(person.PermissionItemControl) { + s.InteractionRespond(i.Interaction, &ErrorNoPermission) + return + } + + if len(i.ApplicationCommandData().Options) <= 0 { + s.InteractionRespond(i.Interaction, &ErrorInvalidArguments) + return + } + + packType := i.ApplicationCommandData().Options[0].StringValue() + if packType == "" { + s.InteractionRespond(i.Interaction, &ErrorInvalidArguments) + return + } + + player := getPersonFromOptions(i.ApplicationCommandData().Options, s) + if player == nil { + s.InteractionRespond(i.Interaction, &ErrorInvalidDisplayOrDiscord) + return + } + + funcLookup := map[string]func(*person.Person){ + "twitch_prime_1": fortnite.GrantRewardTwitchPrime1, + "twitch_prime_2": fortnite.GrantRewardTwitchPrime2, + "samsung_galaxy": fortnite.GrantRewardSamsungGalaxy, + "samsung_ikonik": fortnite.GrantRewardSamsungIkonic, + "honor_guard": fortnite.GrantRewardHonorGuard, + "mfa": fortnite.GrantRewardTwoFactor, + } + + nameLookup := map[string]string{ + "twitch_prime_1": "Twitch Prime Drop 1", + "twitch_prime_2": "Twitch Prime Drop 2", + "samsung_galaxy": "Samsung Galaxy", + "samsung_ikonik": "Samsung IKONIK", + "honor_guard": "Honor Guard", + "mfa": "Multi Factor Authentication", + } + + if handler, ok := funcLookup[packType]; ok { + handler(player) + socket.EmitGiftReceived(player) + s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: player.DisplayName + " has been given the reward `" + nameLookup[packType] + "`.", + }, + }) + return + } } \ No newline at end of file diff --git a/discord/handlers.go b/discord/handlers.go index 02e810c..d179f9d 100644 --- a/discord/handlers.go +++ b/discord/handlers.go @@ -288,6 +288,51 @@ func addCommands() { Handler: permissionHandler, AdminOnly: true, }) + + rewardOptions := append([]*discordgo.ApplicationCommandOption{ + { + Type: discordgo.ApplicationCommandOptionString, + Name: "reward", + Description: "The reward bundle to give to the player.", + Required: true, + Choices: []*discordgo.ApplicationCommandOptionChoice{ + { + Name: "Twitch Prime Drop 1", + Value: "twitch_prime_1", + }, + { + Name: "Twitch Prime Drop 2", + Value: "twitch_prime_2", + }, + { + Name: "Samsung Galaxy", + Value: "samsung_galaxy", + }, + { + Name: "Samsung IKONIK", + Value: "samsung_ikonik", + }, + { + Name: "Honor Guard", + Value: "honor_guard", + }, + { + Name: "Multi Factor Authentication", + Value: "mfa", + }, + }, + }, + }, personOptions...) + + addCommand(&DiscordCommand{ + Command: &discordgo.ApplicationCommand{ + Name: "reward", + Description: "Gift a player a item reward bundle!", + Options: rewardOptions, + }, + Handler: rewardHandler, + AdminOnly: true, + }) } func getPersonFromOptions(opts []*discordgo.ApplicationCommandInteractionDataOption, s *discordgo.Session) *person.Person { diff --git a/fortnite/external.go b/fortnite/external.go index bb13795..0c312c7 100644 --- a/fortnite/external.go +++ b/fortnite/external.go @@ -24,7 +24,7 @@ type ExternalDataClient struct { FortniteItemsWithFeaturedImage []*FortniteItem `json:"-"` TypedFortniteItems map[string][]*FortniteItem `json:"-"` TypedFortniteItemsWithDisplayAssets map[string][]*FortniteItem `json:"-"` - SnowVariantTokens map[string]SnowCosmeticVariantToken `json:"-"` + SnowVariantTokens map[string]*FortniteVariantToken `json:"variants"` } func NewExternalDataClient() *ExternalDataClient { @@ -36,7 +36,7 @@ func NewExternalDataClient() *ExternalDataClient { FortniteItemsWithFeaturedImage: []*FortniteItem{}, TypedFortniteItems: make(map[string][]*FortniteItem), TypedFortniteItemsWithDisplayAssets: make(map[string][]*FortniteItem), - SnowVariantTokens: make(map[string]SnowCosmeticVariantToken), + SnowVariantTokens: make(map[string]*FortniteVariantToken), } } @@ -70,7 +70,7 @@ func (c *ExternalDataClient) LoadExternalData() { c.AddBackpackToItem(item) } - displayAssets := storage.HttpAsset[[]string]("QKnwROGzQjYm1W9xu9uL3VrbSA0tnVj6NJJtEChUdAb3DF8uN.json") + displayAssets := storage.HttpAsset[[]string]("assets.snow.json") if displayAssets == nil { return } @@ -79,11 +79,26 @@ func (c *ExternalDataClient) LoadExternalData() { c.AddDisplayAssetToItem(displayAsset) } - variantTokens := storage.HttpAsset[map[string]SnowCosmeticVariantToken]("QF3nHCFt1vhELoU4q1VKTmpxnk20c2iAiBEBzlbzQAY.json") + variantTokens := storage.HttpAsset[map[string]SnowCosmeticVariantToken]("variants.snow.json") if variantTokens == nil { return } - c.SnowVariantTokens = *variantTokens + + 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 { diff --git a/fortnite/rewards.go b/fortnite/rewards.go new file mode 100644 index 0000000..e2d2ff2 --- /dev/null +++ b/fortnite/rewards.go @@ -0,0 +1,53 @@ +package fortnite + +import p "github.com/ectrc/snow/person" + +func GrantRewardTwitchPrime1(person *p.Person) { + gift := p.NewGift("GiftBox:GB_Twitch", 1, "", "") + gift.AddLoot(p.NewItemWithType("AthenaCharacter:CID_089_Athena_Commando_M_RetroGrey", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaCharacter:CID_085_Athena_Commando_M_Twitch", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaBackpack:BID_029_RetroGrey", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaGlider:Glider_ID_018_Twitch", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaPickaxe:Pickaxe_ID_039_TacticalBlack", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaDance:Emoji_VictoryRoyale", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaDance:Emoji_Wow", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaDance:Emoji_Bush ", 1, "athena")) + person.CommonCoreProfile.Gifts.AddGift(gift).Save() +} + +func GrantRewardTwitchPrime2(person *p.Person) { + gift := p.NewGift("GiftBox:GB_Twitch", 1, "", "") + gift.AddLoot(p.NewItemWithType("AthenaCharacter:CID_114_Athena_Commando_F_TacticalWoodland", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaBackpack:BID_049_TacticalWoodland", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaPickaxe:Pickaxe_ID_044_TacticalUrbanHammer", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaDance:EID_HipHop01", 1, "athena")) + person.CommonCoreProfile.Gifts.AddGift(gift).Save() +} + +func GrantRewardSamsungGalaxy(person *p.Person) { + gift := p.NewGift("GiftBox:GB_SamsungPromo", 1, "", "") + gift.AddLoot(p.NewItemWithType("AthenaCharacter:CID_175_Athena_Commando_M_Celestial", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaBackpack:BID_138_Celestial", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaGlider:Glider_ID_090_Celestial", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaPickaxe:Pickaxe_ID_116_Celestial", 1, "athena")) + person.CommonCoreProfile.Gifts.AddGift(gift).Save() +} + +func GrantRewardSamsungIkonic(person *p.Person) { + gift := p.NewGift("GiftBox:GB_SamsungPromo", 1, "", "") + gift.AddLoot(p.NewItemWithType("AthenaCharacter:CID_313_Athena_Commando_M_KpopFashion", 1, "athena")) + gift.AddLoot(p.NewItemWithType("AthenaDance:EID_KPopDance03", 1, "athena")) + person.CommonCoreProfile.Gifts.AddGift(gift).Save() +} + +func GrantRewardHonorGuard(person *p.Person) { + gift := p.NewGift("GiftBox:GB_HonorPromo", 1, "", "") + gift.AddLoot(p.NewItemWithType("AthenaCharacter:CID_342_Athena_Commando_M_StreetRacerMetallic", 1, "athena")) + person.CommonCoreProfile.Gifts.AddGift(gift).Save() +} + +func GrantRewardTwoFactor(person *p.Person) { + gift := p.NewGift("GiftBox:GB_MfaReward", 1, "", "") + gift.AddLoot(p.NewItemWithType("AthenaDance:EID_BoogieDown", 1, "athena")) + person.CommonCoreProfile.Gifts.AddGift(gift).Save() +} \ No newline at end of file diff --git a/fortnite/types.go b/fortnite/types.go index 161c02f..ceee608 100644 --- a/fortnite/types.go +++ b/fortnite/types.go @@ -80,8 +80,21 @@ type SnowCosmeticVariantToken struct { Channel string `json:"channel"` Value string `json:"value"` } `json:"grants"` + Item string `json:"item"` Name string `json:"name"` Gift bool `json:"gift"` Equip bool `json:"equip"` Unseen bool `json:"unseen"` +} + +type FortniteVariantToken struct { + Grants []struct { + Channel string `json:"channel"` + Value string `json:"value"` + } `json:"grants"` + Item *FortniteItem `json:"item"` + Name string `json:"name"` + Gift bool `json:"gift"` + Equip bool `json:"equip"` + Unseen bool `json:"unseen"` } \ No newline at end of file diff --git a/handlers/auth.go b/handlers/auth.go index 147a3bf..ae82fe3 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -251,12 +251,12 @@ func MiddlewareFortnite(c *fiber.Ctx) error { func MiddlewareWeb(c *fiber.Ctx) error { snowId, err := aid.GetSnowFromToken(c.Get("Authorization")) if err != nil { - return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Invalid Access Token")) + return c.Status(fiber.StatusForbidden).JSON(aid.JSON{"error":"Invalid Access Token"}) } person := p.Find(snowId) if person == nil { - return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Invalid Access Token")) + return c.Status(fiber.StatusForbidden).JSON(aid.JSON{"error":"Invalid Access Token"}) } c.Locals("person", person) diff --git a/handlers/client.go b/handlers/client.go index 1fd7b9d..15b6e6a 100644 --- a/handlers/client.go +++ b/handlers/client.go @@ -279,7 +279,7 @@ func clientSetItemFavoriteStatusBatchAction(c *fiber.Ctx, person *p.Person, prof return nil } -func clientSetCosmeticLockerSlotAction(c *fiber.Ctx, person *p.Person, profile *p.Profile, notifications *[]aid.JSON) error { +func clientSetCosmeticLockerSlotAction(c *fiber.Ctx, person *p.Person, profile *p.Profile, notifications *[]aid.JSON) error { var body struct { Category string `json:"category" binding:"required"` // item type e.g. Character ItemToSlot string `json:"itemToSlot" binding:"required"` // template id @@ -800,15 +800,7 @@ func clientGiftCatalogEntryAction(c *fiber.Ctx, person *p.Person, profile *p.Pro } receiverPerson.CommonCoreProfile.Gifts.AddGift(gift).Save() - - socket, ok := socket.JabberSockets.Get(receiverPerson.ID) - if ok { - socket.JabberSendMessageToPerson(aid.JSON{ - "payload": aid.JSON{}, - "type": "com.epicgames.gift.received", - "timestamp": time.Now().Format("2006-01-02T15:04:05.999Z"), - }) - } + socket.EmitGiftReceived(receiverPerson) } return nil @@ -823,17 +815,18 @@ func clientRemoveGiftBoxAction(c *fiber.Ctx, person *p.Person, profile *p.Profil return fmt.Errorf("invalid Body") } - gift := profile.Gifts.GetGift(body.GiftBoxItemId) + gift := person.CommonCoreProfile.Gifts.GetGift(body.GiftBoxItemId) if gift == nil { return fmt.Errorf("gift not found") } + aid.Print(gift.TemplateID) + for _, item := range gift.Loot { person.GetProfileFromType(item.ProfileType).Items.AddItem(item).Save() } - profile.Gifts.DeleteGift(gift.ID) - + person.CommonCoreProfile.Gifts.DeleteGift(gift.ID) return nil } diff --git a/handlers/snow.go b/handlers/snow.go index fbc87c0..54b6684 100644 --- a/handlers/snow.go +++ b/handlers/snow.go @@ -4,7 +4,6 @@ import ( "github.com/ectrc/snow/aid" "github.com/ectrc/snow/fortnite" p "github.com/ectrc/snow/person" - "github.com/ectrc/snow/storage" "github.com/gofiber/fiber/v2" ) @@ -20,28 +19,6 @@ func GetSnowPreloadedCosmetics(c *fiber.Ctx) error { return c.JSON(fortnite.External) } -func GetPlayerLocker(c *fiber.Ctx) error { - person := c.Locals("person").(*p.Person) - - items := make([]p.Item, 0) - person.AthenaProfile.Items.RangeItems(func(key string, value *p.Item) bool { - items = append(items, *value) - return true - }) - - return c.JSON(items) -} - -func GetPlayer(c *fiber.Ctx) error { - person := c.Locals("person").(*p.Person) - - return c.JSON(aid.JSON{ - "id": person.ID, - "displayName": person.DisplayName, - "discord": person.Discord, - }) -} - func GetSnowCachedPlayers(c *fiber.Ctx) error { persons := p.AllFromCache() players := make([]p.PersonSnapshot, len(persons)) @@ -50,14 +27,7 @@ func GetSnowCachedPlayers(c *fiber.Ctx) error { players[i] = *person.Snapshot() } - return c.JSON(players) -} - -func GetSnowConfig(c *fiber.Ctx) error { - return c.JSON(aid.JSON{ - "basic": aid.Config, - "amazon": storage.Repo.Amazon, - }) + return c.Status(200).JSON(players) } func GetSnowParties(c *fiber.Ctx) error { @@ -74,4 +44,15 @@ func GetSnowParties(c *fiber.Ctx) error { func GetSnowShop(c *fiber.Ctx) error { shop := fortnite.NewRandomFortniteCatalog() return c.JSON(shop.GenerateFortniteCatalog()) +} + +// + +func GetPlayer(c *fiber.Ctx) error { + person := c.Locals("person").(*p.Person) + return c.Status(200).JSON(person.Snapshot()) +} + +func GetPlayerOkay(c *fiber.Ctx) error { + return c.Status(200).SendString("okay") } \ No newline at end of file diff --git a/main.go b/main.go index 6e7390d..49aca0f 100644 --- a/main.go +++ b/main.go @@ -50,7 +50,7 @@ func init() { for _, username := range aid.Config.Accounts.Gods { found := person.FindByDisplay(username) if found == nil { - found = fortnite.NewFortnitePersonWithId(username, username, true) + found = fortnite.NewFortnitePersonWithId(username, username, aid.Config.Fortnite.Everything) } found.AddPermission(person.PermissionAllWithRoles) @@ -63,7 +63,7 @@ func init() { continue } - found.AddPermission(person.PermissionOwner) + found.AddPermission(person.PermissionAllWithRoles) aid.Print("(snow) owner account " + username + " loaded") } } @@ -168,21 +168,21 @@ func main() { party.Post("/members/:friendId/intentions/:accountId", handlers.PostPartyCreateIntention) snow := r.Group("/snow") - snow.Use(handlers.MiddlewareOnlyDebug) - snow.Get("/cache", handlers.GetSnowCachedPlayers) - snow.Get("/config", handlers.GetSnowConfig) - snow.Get("/sockets", handlers.GetSnowConnectedSockets) - snow.Get("/cosmetics", handlers.GetSnowPreloadedCosmetics) - snow.Get("/parties", handlers.GetSnowParties) - snow.Get("/shop", handlers.GetSnowShop) - discord := snow.Group("/discord") discord.Get("/", handlers.GetDiscordOAuthURL) player := snow.Group("/player") player.Use(handlers.MiddlewareWeb) player.Get("/", handlers.GetPlayer) - player.Get("/locker", handlers.GetPlayerLocker) + player.Get("/okay", handlers.GetPlayerOkay) + + debug := snow.Group("/") + debug.Use(handlers.MiddlewareOnlyDebug) + debug.Get("/cache", handlers.GetSnowCachedPlayers) + debug.Get("/sockets", handlers.GetSnowConnectedSockets) + debug.Get("/cosmetics", handlers.GetSnowPreloadedCosmetics) + debug.Get("/parties", handlers.GetSnowParties) + debug.Get("/shop", handlers.GetSnowShop) r.Hooks().OnListen(func(ld fiber.ListenData) error { aid.Print("(fiber) listening on " + aid.Config.API.Host + ":" + ld.Port) diff --git a/person/gift.go b/person/gift.go index 5179a24..32b190d 100644 --- a/person/gift.go +++ b/person/gift.go @@ -120,6 +120,9 @@ func (g *Gift) Save() { } storage.Repo.SaveGift(g.ToDatabase(g.ProfileID)) + for _, item := range g.Loot { + item.SaveLoot(g.ID) + } } func (g *Gift) Snapshot() GiftSnapshot { diff --git a/person/person.go b/person/person.go index c69b492..e5ebc85 100644 --- a/person/person.go +++ b/person/person.go @@ -227,6 +227,7 @@ func findHelper(databasePerson *storage.DB_Person, shallow bool, save bool) *Per if save { cache.SavePerson(person) } + return person } @@ -448,6 +449,7 @@ func (p *Person) Snapshot() *PersonSnapshot { snapshot := &PersonSnapshot{ ID: p.ID, DisplayName: p.DisplayName, + RefundTickets: p.RefundTickets, Permissions: int64(p.Permissions), AthenaProfile: *p.AthenaProfile.Snapshot(), CommonCoreProfile: *p.CommonCoreProfile.Snapshot(), @@ -457,6 +459,10 @@ func (p *Person) Snapshot() *PersonSnapshot { CreativeProfile: *p.CreativeProfile.Snapshot(), BanHistory: []storage.DB_BanStatus{}, Discord: *p.Discord, + Relationships: *p.Relationships.Snapshot(), + Parties: *p.Parties.Snapshot(), + Invites: *p.Invites.Snapshot(), + Intentions: *p.Intentions.Snapshot(), } p.BanHistory.Range(func(key string, ban *storage.DB_BanStatus) bool { diff --git a/person/snapshot.go b/person/snapshot.go index 9596007..48117e8 100644 --- a/person/snapshot.go +++ b/person/snapshot.go @@ -5,6 +5,7 @@ import "github.com/ectrc/snow/storage" type PersonSnapshot struct { ID string DisplayName string + RefundTickets int Permissions int64 AthenaProfile ProfileSnapshot CommonCoreProfile ProfileSnapshot @@ -14,6 +15,10 @@ type PersonSnapshot struct { CreativeProfile ProfileSnapshot BanHistory []storage.DB_BanStatus Discord storage.DB_DiscordPerson + Relationships map[string]*Relationship + Parties map[string]*Party + Invites map[string]*PartyInvite + Intentions map[string]*PartyIntention } type ProfileSnapshot struct { diff --git a/socket/events.go b/socket/events.go index cd15c30..bfcf3a0 100644 --- a/socket/events.go +++ b/socket/events.go @@ -7,6 +7,19 @@ import ( "github.com/ectrc/snow/person" ) +func EmitGiftReceived(person *person.Person) { + s, ok := JabberSockets.Get(person.ID) + if !ok { + return + } + + s.JabberSendMessageToPerson(aid.JSON{ + "payload": aid.JSON{}, + "type": "com.epicgames.gift.received", + "timestamp": time.Now().Format("2006-01-02T15:04:05.999Z"), + }) +} + func EmitPartyMemberJoined(party *person.Party, joiningMember *person.PartyMember) { for _, partyMember := range party.Members { s, ok := JabberSockets.Get(partyMember.Person.ID) diff --git a/storage/hotfix.go b/storage/hotfix.go index 3311526..bd49bcc 100644 --- a/storage/hotfix.go +++ b/storage/hotfix.go @@ -103,6 +103,11 @@ bShouldCheckIfPlatformAllowed=false`) func GetDefaultRuntime() []byte { return []byte(` [/Script/FortniteGame.FortRuntimeOptions] +!DisabledFrontendNavigationTabs=ClearArray +;+DisabledFrontendNavigationTabs=(TabName="AthenaChallenges",TabState=EFortRuntimeOptionTabState::Hidden) +;+DisabledFrontendNavigationTabs=(TabName="Showdown",TabState=EFortRuntimeOptionTabState::Hidden) +;+DisabledFrontendNavigationTabs=(TabName="AthenaStore",TabState=EFortRuntimeOptionTabState::Hidden) + bEnableGlobalChat=true bDisableGifting=false bDisableGiftingPC=false