Improve Database Queries by 1000x; Add support for newer seasons; Lockers nearly implemented.
This commit is contained in:
parent
e2707473aa
commit
5508ad4348
|
@ -10,7 +10,7 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
oatuhTokenGrantTypes = map[string]func(c *fiber.Ctx, body *OAuthTokenBody) error{
|
||||
oauthTokenGrantTypes = map[string]func(c *fiber.Ctx, body *OAuthTokenBody) error{
|
||||
"client_credentials": PostOAuthTokenClientCredentials,
|
||||
"password": PostOAuthTokenPassword,
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ func PostOAuthToken(c *fiber.Ctx) error {
|
|||
return c.Status(fiber.StatusBadRequest).JSON(aid.ErrorBadRequest("Invalid Request Body"))
|
||||
}
|
||||
|
||||
if action, ok := oatuhTokenGrantTypes[body.GrantType]; ok {
|
||||
if action, ok := oauthTokenGrantTypes[body.GrantType]; ok {
|
||||
return action(c, &body)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/ectrc/snow/aid"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
@ -26,7 +28,7 @@ func GetFortniteReceipts(c *fiber.Ctx) error {
|
|||
}
|
||||
|
||||
func GetMatchmakingSession(c *fiber.Ctx) error {
|
||||
return c.Status(fiber.StatusOK).JSON([]string{})
|
||||
return c.Status(fiber.StatusOK).Send([]byte{})
|
||||
}
|
||||
|
||||
func GetFortniteVersion(c *fiber.Ctx) error {
|
||||
|
@ -35,8 +37,24 @@ func GetFortniteVersion(c *fiber.Ctx) error {
|
|||
})
|
||||
}
|
||||
|
||||
func GetWaitingRoomStatus(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusNoContent)
|
||||
}
|
||||
|
||||
func GetRegion(c *fiber.Ctx) error {
|
||||
return c.Status(fiber.StatusOK).JSON(aid.JSON{
|
||||
"continent": aid.JSON{
|
||||
"code": "EU",
|
||||
},
|
||||
"country": aid.JSON{
|
||||
"iso_code": "GB",
|
||||
},
|
||||
"subdivisions": []aid.JSON{},
|
||||
})
|
||||
}
|
||||
|
||||
func GetContentPages(c *fiber.Ctx) error {
|
||||
// seasonString := strconv.Itoa(aid.Config.Fortnite.Season)
|
||||
seasonString := strconv.Itoa(aid.Config.Fortnite.Season)
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(aid.JSON{
|
||||
"battlepassaboutmessages": aid.JSON{
|
||||
|
@ -77,14 +95,14 @@ func GetContentPages(c *fiber.Ctx) error {
|
|||
},
|
||||
"dynamicbackgrounds": aid.JSON{
|
||||
"backgrounds": aid.JSON{"backgrounds": []aid.JSON{
|
||||
// {
|
||||
// "key": "lobby",
|
||||
// "stage": "season"+seasonString,
|
||||
// },
|
||||
// {
|
||||
// "key": "vault",
|
||||
// "stage": "season"+seasonString,
|
||||
// },
|
||||
{
|
||||
"key": "lobby",
|
||||
"stage": "season" + seasonString,
|
||||
},
|
||||
{
|
||||
"key": "vault",
|
||||
"stage": "season" + seasonString,
|
||||
},
|
||||
}},
|
||||
"lastModified": "0000-00-00T00:00:00.000Z",
|
||||
},
|
||||
|
|
|
@ -29,28 +29,35 @@ func PostProfileAction(c *fiber.Ctx) error {
|
|||
}
|
||||
|
||||
profile := person.GetProfileFromType(c.Query("profileId"))
|
||||
if action, ok := profileActions[c.Params("action")]; ok && profile != nil {
|
||||
defer profile.ClearProfileChanges()
|
||||
|
||||
before := profile.Snapshot()
|
||||
if action, ok := profileActions[c.Params("action")]; ok {
|
||||
if err := action(c, person, profile); err != nil {
|
||||
return c.Status(400).JSON(aid.ErrorBadRequest(err.Error()))
|
||||
}
|
||||
}
|
||||
profile.Diff(before)
|
||||
}
|
||||
|
||||
revision, _ := strconv.Atoi(c.Query("rvn"))
|
||||
if revision == -1 {
|
||||
if revision == -1 && profile == nil {
|
||||
revision = 1
|
||||
}
|
||||
if revision == -1 && profile != nil {
|
||||
revision = profile.Revision
|
||||
}
|
||||
revision++
|
||||
|
||||
changes := []interface{}{}
|
||||
if profile != nil {
|
||||
changes = profile.Changes
|
||||
}
|
||||
|
||||
return c.Status(200).JSON(aid.JSON{
|
||||
"profileId": profile.Type,
|
||||
"profileId": c.Query("profileId"),
|
||||
"profileRevision": revision,
|
||||
"profileCommandRevision": revision,
|
||||
"profileChangesBaseRevision": revision - 1,
|
||||
"profileChanges": profile.Changes,
|
||||
"profileChanges": changes,
|
||||
"multiUpdate": []aid.JSON{},
|
||||
"notifications": []aid.JSON{},
|
||||
"responseVersion": 1,
|
||||
|
|
|
@ -1,12 +1,119 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/ectrc/snow/aid"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
TEMP_STORAGE = map[string][]byte{
|
||||
"DefaultEngine.ini": []byte(`
|
||||
[OnlineSubsystemMcp.Xmpp Prod]
|
||||
bUseSSL=false
|
||||
ServerAddr="ws://127.0.0.1:80"
|
||||
ServerPort="80"
|
||||
|
||||
[OnlineSubsystemMcp.Xmpp]
|
||||
bUseSSL=false
|
||||
ServerAddr="ws://127.0.0.1:80"
|
||||
ServerPort="80"
|
||||
|
||||
[/Script/Qos.QosRegionManager]
|
||||
NumTestsPerRegion=5
|
||||
PingTimeout=3.0
|
||||
|
||||
[XMPP]
|
||||
bEnableWebsockets=true
|
||||
|
||||
[OnlineSubsystemMcp]
|
||||
bUsePartySystemV2=false
|
||||
|
||||
[OnlineSubsystemMcp.OnlinePartySystemMcpAdapter]
|
||||
bUsePartySystemV2=false
|
||||
|
||||
[ConsoleVariables]
|
||||
n.VerifyPeer=0
|
||||
FortMatchmakingV2.ContentBeaconFailureCancelsMatchmaking=0
|
||||
Fort.ShutdownWhenContentBeaconFails=0
|
||||
FortMatchmakingV2.EnableContentBeacon=0
|
||||
`),
|
||||
"DefaultGame.ini": []byte(`
|
||||
[/Script/FortniteGame.FortOnlineAccount]
|
||||
bEnableEulaCheck=false
|
||||
|
||||
[/Script/FortniteGame.FortChatManager]
|
||||
bShouldRequestGeneralChatRooms=false
|
||||
bShouldJoinGlobalChat=flase
|
||||
bShouldJoinFounderChat=false
|
||||
bIsAthenaGlobalChatEnabled=false
|
||||
|
||||
[/Script/FortniteGame.FortGameInstance]
|
||||
!FrontEndPlaylistData=ClearArray
|
||||
+FrontEndPlaylistData=(PlaylistName=Playlist_DefaultSolo, PlaylistAccess=(bEnabled=True, bIsDefaultPlaylist=True, bVisibleWhenDisabled=True, bDisplayAsNew=False, CategoryIndex=0, bDisplayAsLimitedTime=False, DisplayPriority=0))
|
||||
+FrontEndPlaylistData=(PlaylistName=Playlist_DefaultDuo, PlaylistAccess=(bEnabled=False, bIsDefaultPlaylist=True, bVisibleWhenDisabled=True, bDisplayAsNew=False, CategoryIndex=0, bDisplayAsLimitedTime=False, DisplayPriority=1))
|
||||
+FrontEndPlaylistData=(PlaylistName=Playlist_DefaultSquad, PlaylistAccess=(bEnabled=False, bIsDefaultPlaylist=True, bVisibleWhenDisabled=True, bDisplayAsNew=False, CategoryIndex=0, bDisplayAsLimitedTime=False, DisplayPriority=2))
|
||||
+FrontEndPlaylistData=(PlaylistName=Playlist_Fill_Squads, PlaylistAccess=(bEnabled=False, bIsDefaultPlaylist=False, bVisibleWhenDisabled=True, bDisplayAsNew=False, CategoryIndex=1, bDisplayAsLimitedTime=False, DisplayPriority=0))
|
||||
+FrontEndPlaylistData=(PlaylistName=Playlist_Blitz_Solo, PlaylistAccess=(bEnabled=True, bIsDefaultPlaylist=False, bVisibleWhenDisabled=True, bDisplayAsNew=True, CategoryIndex=1, bDisplayAsLimitedTime=True, DisplayPriority=1))
|
||||
`),
|
||||
"DefaultRuntimeOptions.ini": []byte(`
|
||||
[/Script/FortniteGame.FortRuntimeOptions]
|
||||
bEnableGlobalChat=false
|
||||
bDisableGifting=false
|
||||
bDisableGiftingPC=false
|
||||
bDisableGiftingPS4=false
|
||||
bDisableGiftingXB=false`),
|
||||
}
|
||||
)
|
||||
|
||||
func GetCloudStorageFiles(c *fiber.Ctx) error {
|
||||
return c.Status(fiber.StatusOK).JSON([]aid.JSON{})
|
||||
engineHash := sha1.Sum(TEMP_STORAGE["DefaultEngine.ini"])
|
||||
engineHash256 := sha1.Sum(TEMP_STORAGE["DefaultEngine.ini"])
|
||||
gameHash := sha1.Sum(TEMP_STORAGE["DefaultGame.ini"])
|
||||
gameHash256 := sha1.Sum(TEMP_STORAGE["DefaultGame.ini"])
|
||||
runtimeHash := sha1.Sum(TEMP_STORAGE["DefaultRuntimeOptions.ini"])
|
||||
runtimeHash256 := sha1.Sum(TEMP_STORAGE["DefaultRuntimeOptions.ini"])
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON([]aid.JSON{
|
||||
{
|
||||
"uniqueFilename": "DefaultEngine.ini",
|
||||
"filename": "DefaultEngine.ini",
|
||||
"hash": hex.EncodeToString(engineHash[:]),
|
||||
"hash256": hex.EncodeToString(engineHash256[:]),
|
||||
"length": len(TEMP_STORAGE["DefaultEngine.ini"]),
|
||||
"contentType": "application/octet-stream",
|
||||
"uploaded": "2021-01-01T00:00:00.000Z",
|
||||
"storageType": "S3",
|
||||
"doNotCache": false,
|
||||
"storageIds": []string{"primary"},
|
||||
},
|
||||
{
|
||||
"uniqueFilename": "DefaultGame.ini",
|
||||
"filename": "DefaultGame.ini",
|
||||
"hash": hex.EncodeToString(gameHash[:]),
|
||||
"hash256": hex.EncodeToString(gameHash256[:]),
|
||||
"length": len(TEMP_STORAGE["DefaultGame.ini"]),
|
||||
"contentType": "application/octet-stream",
|
||||
"uploaded": "2021-01-01T00:00:00.000Z",
|
||||
"storageType": "S3",
|
||||
"doNotCache": false,
|
||||
"storageIds": []string{"primary"},
|
||||
},
|
||||
{
|
||||
"uniqueFilename": "DefaultRuntimeOptions.ini",
|
||||
"filename": "DefaultRuntimeOptions.ini",
|
||||
"hash": hex.EncodeToString(runtimeHash[:]),
|
||||
"hash256": hex.EncodeToString(runtimeHash256[:]),
|
||||
"length": len(TEMP_STORAGE["DefaultRuntimeOptions.ini"]),
|
||||
"contentType": "application/octet-stream",
|
||||
"uploaded": "2021-01-01T00:00:00.000Z",
|
||||
"storageType": "S3",
|
||||
"doNotCache": false,
|
||||
"storageIds": []string{"primary"},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func GetCloudStorageConfig(c *fiber.Ctx) error {
|
||||
|
@ -28,7 +135,12 @@ func GetCloudStorageFile(c *fiber.Ctx) error {
|
|||
return c.Status(fiber.StatusBadRequest).JSON(aid.ErrorBadRequest)
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(aid.JSON{})
|
||||
file, ok := TEMP_STORAGE[fileName]
|
||||
if !ok {
|
||||
return c.Status(fiber.StatusNotFound).JSON(aid.ErrorNotFound)
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).Send(file)
|
||||
}
|
||||
|
||||
func GetUserStorageFiles(c *fiber.Ctx) error {
|
||||
|
|
8
main.go
8
main.go
|
@ -45,6 +45,14 @@ func main() {
|
|||
r.Use(aid.FiberCors())
|
||||
|
||||
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.Get("/snow/cache", func(c *fiber.Ctx) error {
|
||||
cache := person.AllFromCache()
|
||||
return c.JSON(cache)
|
||||
})
|
||||
|
||||
account := r.Group("/account/api")
|
||||
account.Get("/public/account", handlers.GetPublicAccounts)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package person
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/ectrc/snow/aid"
|
||||
"github.com/ectrc/snow/storage"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -25,7 +27,7 @@ func NewFortnitePerson(displayName string, key string) *Person {
|
|||
person.DisplayName = displayName
|
||||
person.AccessKey = key
|
||||
|
||||
person.Profile0Profile.Items.AddItem(NewItem("Currency:MtxPurchased", 0)) // for season 2 and bellow
|
||||
person.Profile0Profile.Items.AddItem(NewItem("Currency:MtxPurchased", 0)).Save() // for season 2 and bellow
|
||||
|
||||
for _, item := range defaultAthenaItems {
|
||||
person.AthenaProfile.Items.AddItem(NewItem(item, 1))
|
||||
|
@ -34,77 +36,91 @@ func NewFortnitePerson(displayName string, key string) *Person {
|
|||
for _, item := range defaultCommonCoreItems {
|
||||
if item == "HomebaseBannerIcon:StandardBanner" {
|
||||
for i := 1; i < 32; i++ {
|
||||
person.CommonCoreProfile.Items.AddItem(NewItem(item+strconv.Itoa(i), 1))
|
||||
person.CommonCoreProfile.Items.AddItem(NewItem(item+strconv.Itoa(i), 1)).Save()
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if item == "HomebaseBannerColor:DefaultColor" {
|
||||
for i := 1; i < 22; i++ {
|
||||
person.CommonCoreProfile.Items.AddItem(NewItem(item+strconv.Itoa(i), 1))
|
||||
person.CommonCoreProfile.Items.AddItem(NewItem(item+strconv.Itoa(i), 1)).Save()
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if item == "Currency:MtxPurchased" {
|
||||
person.CommonCoreProfile.Items.AddItem(NewItem(item, 0))
|
||||
person.CommonCoreProfile.Items.AddItem(NewItem(item, 0)).Save()
|
||||
continue
|
||||
}
|
||||
|
||||
person.CommonCoreProfile.Items.AddItem(NewItem(item, 1))
|
||||
person.CommonCoreProfile.Items.AddItem(NewItem(item, 1)).Save()
|
||||
}
|
||||
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("mfa_reward_claimed", true))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("rested_xp_overflow", 0))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("lifetime_wins", 0))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("party_assist_quest", ""))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("quest_manager", aid.JSON{}))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("inventory_limit_bonus", 0))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("daily_rewards", []aid.JSON{}))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("competitive_identity", aid.JSON{}))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_update", 0))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_num", aid.Config.Fortnite.Season))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("permissions", []aid.JSON{}))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("mfa_reward_claimed", true)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("rested_xp_overflow", 0)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("lifetime_wins", 0)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("party_assist_quest", "")).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("quest_manager", aid.JSON{})).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("inventory_limit_bonus", 0)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("daily_rewards", []aid.JSON{})).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("competitive_identity", aid.JSON{})).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("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("loadouts", []aid.JSON{}))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("last_applied_loadout", ""))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("active_loadout_index", 0))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("accountLevel", 1)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("level", 1)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("xp", 0)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("xp_overflow", 0)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("rested_xp", 0)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("rested_xp_mult", 0)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("rested_xp_exchange", 0)).Save()
|
||||
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("accountLevel", 1))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("level", 1))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("xp", 0))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("xp_overflow", 0))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("rested_xp", 0))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("rested_xp_mult", 0))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("rested_xp_exchange", 0))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("book_purchased", false)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("book_level", 1)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("book_xp", 0)).Save()
|
||||
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("book_purchased", false))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("book_level", 1))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("book_xp", 0))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_character", person.AthenaProfile.Items.GetItemByTemplateID("AthenaCharacter:CID_001_Athena_Commando_F_Default").ID)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_backpack", "")).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_pickaxe", person.AthenaProfile.Items.GetItemByTemplateID("AthenaPickaxe:DefaultPickaxe").ID)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_glider", person.AthenaProfile.Items.GetItemByTemplateID("AthenaGlider:DefaultGlider").ID)).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_skydivecontrail", "")).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_dance", make([]string, 6))).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_itemwraps", make([]string, 7))).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_loadingscreen", "")).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_musicpack", "")).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("banner_icon", "")).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("banner_color", "")).Save()
|
||||
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_character", person.AthenaProfile.Items.GetItemByTemplateID("AthenaCharacter:CID_001_Athena_Commando_F_Default").ID))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_backpack", ""))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_pickaxe", person.AthenaProfile.Items.GetItemByTemplateID("AthenaPickaxe:DefaultPickaxe").ID))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_glider", person.AthenaProfile.Items.GetItemByTemplateID("AthenaGlider:DefaultGlider").ID))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_skydivecontrail", ""))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_dance", make([]string, 6)))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_itemwraps", make([]string, 7)))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_loadingscreen", ""))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_musicpack", ""))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("banner_icon", ""))
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("banner_color", ""))
|
||||
|
||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("mfa_enabled", true))
|
||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("mtx_affiliate", ""))
|
||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("mfa_enabled", true)).Save()
|
||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("mtx_affiliate", "")).Save()
|
||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("mtx_purchase_history", aid.JSON{
|
||||
"refundsUsed": 0,
|
||||
"refundCredits": 3,
|
||||
"purchases": []any{},
|
||||
}))
|
||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("current_mtx_platform", "EpicPC"))
|
||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("allowed_to_receive_gifts", true))
|
||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("allowed_to_send_gifts", true))
|
||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("gift_history", aid.JSON{}))
|
||||
})).Save()
|
||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("current_mtx_platform", "EpicPC")).Save()
|
||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("allowed_to_receive_gifts", true)).Save()
|
||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("allowed_to_send_gifts", true)).Save()
|
||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("gift_history", aid.JSON{})).Save()
|
||||
|
||||
loadout := NewLoadout("sandbox_loadout", person.AthenaProfile)
|
||||
person.AthenaProfile.Loadouts.AddLoadout(loadout).Save()
|
||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("loadouts", []string{
|
||||
loadout.ID,
|
||||
})).Save()
|
||||
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()
|
||||
}
|
||||
|
||||
person.Save()
|
||||
|
||||
|
|
|
@ -70,21 +70,12 @@ func FromDatabaseLoot(item *storage.DB_Loot) *Item {
|
|||
}
|
||||
|
||||
func (i *Item) GenerateFortniteItemEntry() aid.JSON {
|
||||
variants := []aid.JSON{}
|
||||
attributes := aid.JSON{
|
||||
"variants": variants,
|
||||
"variants": i.GenerateFortniteItemVariantChannels(),
|
||||
"favorite": i.Favorite,
|
||||
"item_seen": i.HasSeen,
|
||||
}
|
||||
|
||||
for _, variant := range i.Variants {
|
||||
variants = append(variants, aid.JSON{
|
||||
"channel": variant.Channel,
|
||||
"owned": variant.Owned,
|
||||
"active": variant.Active,
|
||||
})
|
||||
}
|
||||
|
||||
if i.TemplateID == "Currency:MtxPurchased" {
|
||||
attributes = aid.JSON{
|
||||
"platform": "Shared",
|
||||
|
@ -98,6 +89,20 @@ func (i *Item) GenerateFortniteItemEntry() aid.JSON {
|
|||
}
|
||||
}
|
||||
|
||||
func (i *Item) GenerateFortniteItemVariantChannels() []aid.JSON {
|
||||
variants := []aid.JSON{}
|
||||
|
||||
for _, variant := range i.Variants {
|
||||
variants = append(variants, aid.JSON{
|
||||
"channel": variant.Channel,
|
||||
"owned": variant.Owned,
|
||||
"active": variant.Active,
|
||||
})
|
||||
}
|
||||
|
||||
return variants
|
||||
}
|
||||
|
||||
func (i *Item) GetAttribute(attribute string) interface{} {
|
||||
switch attribute {
|
||||
case "Favorite":
|
||||
|
|
244
person/loadout.go
Normal file
244
person/loadout.go
Normal file
|
@ -0,0 +1,244 @@
|
|||
package person
|
||||
|
||||
import (
|
||||
"github.com/ectrc/snow/aid"
|
||||
"github.com/ectrc/snow/storage"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Loadout struct {
|
||||
ID string
|
||||
ProfileID string
|
||||
TemplateID string
|
||||
LockerName string
|
||||
BannerID string
|
||||
BannerColorID string
|
||||
CharacterID string
|
||||
PickaxeID string
|
||||
BackpackID string
|
||||
GliderID string
|
||||
DanceID []string
|
||||
ItemWrapID []string
|
||||
ContrailID string
|
||||
LoadingScreenID string
|
||||
MusicPackID string
|
||||
}
|
||||
|
||||
func NewLoadout(name string, athena *Profile) *Loadout {
|
||||
character := athena.Attributes.GetAttributeByKey("favorite_character")
|
||||
pickaxe := athena.Attributes.GetAttributeByKey("favorite_pickaxe")
|
||||
backpack := athena.Attributes.GetAttributeByKey("favorite_backpack")
|
||||
glider := athena.Attributes.GetAttributeByKey("favorite_glider")
|
||||
contrail := athena.Attributes.GetAttributeByKey("favorite_skydivecontrail")
|
||||
screen := athena.Attributes.GetAttributeByKey("favorite_loadingscreen")
|
||||
music := athena.Attributes.GetAttributeByKey("favorite_musicpack")
|
||||
|
||||
icon := athena.Attributes.GetAttributeByKey("banner_icon")
|
||||
color := athena.Attributes.GetAttributeByKey("banner_color")
|
||||
|
||||
dances := athena.Attributes.GetAttributeByKey("favorite_dance")
|
||||
wraps := athena.Attributes.GetAttributeByKey("favorite_itemwraps")
|
||||
|
||||
dancesReal := aid.JSONParse(dances.ValueJSON).([]any)
|
||||
wrapsReal := aid.JSONParse(wraps.ValueJSON).([]any)
|
||||
|
||||
dancesValue := make([]string, len(dancesReal))
|
||||
wrapsValue := make([]string, len(wrapsReal))
|
||||
|
||||
for i, v := range dancesReal {
|
||||
value, ok := v.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
dancesValue[i] = value
|
||||
}
|
||||
|
||||
for i, v := range wrapsReal {
|
||||
value, ok := v.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
wrapsValue[i] = value
|
||||
}
|
||||
|
||||
return &Loadout{
|
||||
ID: uuid.New().String(),
|
||||
ProfileID: athena.ID,
|
||||
TemplateID: "CosmeticLocker:CosmeticLocker_Athena",
|
||||
LockerName: name,
|
||||
CharacterID: aid.JSONParse(character.ValueJSON).(string),
|
||||
PickaxeID: aid.JSONParse(pickaxe.ValueJSON).(string),
|
||||
BackpackID: aid.JSONParse(backpack.ValueJSON).(string),
|
||||
GliderID: aid.JSONParse(glider.ValueJSON).(string),
|
||||
ContrailID: aid.JSONParse(contrail.ValueJSON).(string),
|
||||
LoadingScreenID: aid.JSONParse(screen.ValueJSON).(string),
|
||||
MusicPackID: aid.JSONParse(music.ValueJSON).(string),
|
||||
BannerID: aid.JSONParse(icon.ValueJSON).(string),
|
||||
BannerColorID: aid.JSONParse(color.ValueJSON).(string),
|
||||
DanceID: dancesValue,
|
||||
ItemWrapID: wrapsValue,
|
||||
}
|
||||
}
|
||||
|
||||
func FromDatabaseLoadout(loadout *storage.DB_Loadout) *Loadout {
|
||||
return &Loadout{
|
||||
ID: loadout.ID,
|
||||
ProfileID: loadout.ProfileID,
|
||||
TemplateID: loadout.TemplateID,
|
||||
LockerName: loadout.LockerName,
|
||||
BannerID: loadout.BannerID,
|
||||
BannerColorID: loadout.BannerColorID,
|
||||
CharacterID: loadout.CharacterID,
|
||||
PickaxeID: loadout.PickaxeID,
|
||||
BackpackID: loadout.BackpackID,
|
||||
GliderID: loadout.GliderID,
|
||||
DanceID: loadout.DanceID,
|
||||
ItemWrapID: loadout.ItemWrapID,
|
||||
ContrailID: loadout.ContrailID,
|
||||
LoadingScreenID: loadout.LoadingScreenID,
|
||||
MusicPackID: loadout.MusicPackID,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Loadout) GenerateFortniteLoadoutEntry() aid.JSON {
|
||||
json := aid.JSON{
|
||||
"templateId": l.TemplateID,
|
||||
"attributes": aid.JSON{
|
||||
"locker_name": l.LockerName,
|
||||
"banner_icon_template": l.BannerID,
|
||||
"banner_color_template": l.BannerColorID,
|
||||
"locker_slots_data": l.GenerateFortniteLockerSlotsData(),
|
||||
"item_seen": true,
|
||||
},
|
||||
"quantity": 1,
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
||||
func (l *Loadout) GetAttribute(attribute string) interface{} {
|
||||
switch attribute {
|
||||
case "locker_name":
|
||||
return l.LockerName
|
||||
case "banner_icon_template":
|
||||
return l.BannerID
|
||||
case "banner_color_template":
|
||||
return l.BannerColorID
|
||||
case "locker_slots_data":
|
||||
return l.GenerateFortniteLockerSlotsData()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Loadout) GenerateFortniteLockerSlotsData() aid.JSON {
|
||||
return aid.JSON{
|
||||
"slots": aid.JSON{
|
||||
"Character": l.GetItemSlotData(l.CharacterID),
|
||||
"Backpack": l.GetItemSlotData(l.BackpackID),
|
||||
"Pickaxe": l.GetItemSlotData(l.PickaxeID),
|
||||
"Glider": l.GetItemSlotData(l.GliderID),
|
||||
"ItemWrap": l.GetItemsSlotData(l.ItemWrapID),
|
||||
"Dance": l.GetItemsSlotData(l.DanceID),
|
||||
"SkyDiveContrail": l.GetItemSlotData(l.ContrailID),
|
||||
"LoadingScreen": l.GetItemSlotData(l.LoadingScreenID),
|
||||
"MusicPack": l.GetItemSlotData(l.MusicPackID),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Loadout) GetItemSlotData(itemId string) aid.JSON {
|
||||
json := aid.JSON{
|
||||
"items": []string{},
|
||||
"activeVariants": []aid.JSON{},
|
||||
}
|
||||
|
||||
person := Find(l.ProfileID)
|
||||
if person == nil {
|
||||
return json
|
||||
}
|
||||
|
||||
item := person.AthenaProfile.Items.GetItem(itemId)
|
||||
if item == nil {
|
||||
return json
|
||||
}
|
||||
|
||||
items := json["items"].([]string)
|
||||
items = append(items, item.TemplateID)
|
||||
activeVariants := json["activeVariants"].([]aid.JSON)
|
||||
activeVariants = append(activeVariants, aid.JSON{
|
||||
"variants": item.GenerateFortniteItemVariantChannels(),
|
||||
})
|
||||
|
||||
json["items"] = items
|
||||
json["activeVariants"] = activeVariants
|
||||
|
||||
return json
|
||||
}
|
||||
|
||||
func (l *Loadout) GetItemsSlotData(itemIds []string) aid.JSON {
|
||||
json := aid.JSON{
|
||||
"items": []string{},
|
||||
"activeVariants": []aid.JSON{},
|
||||
}
|
||||
|
||||
person := Find(l.ProfileID)
|
||||
if person == nil {
|
||||
return json
|
||||
}
|
||||
|
||||
for _, itemId := range itemIds {
|
||||
item := person.AthenaProfile.Items.GetItem(itemId)
|
||||
if item == nil {
|
||||
item = &Item{
|
||||
ProfileID: l.ProfileID,
|
||||
Variants: []*VariantChannel{},
|
||||
}
|
||||
}
|
||||
|
||||
items := json["items"].([]string)
|
||||
items = append(items, item.TemplateID)
|
||||
|
||||
activeVariants := json["activeVariants"].([]aid.JSON)
|
||||
activeVariants = append(activeVariants, aid.JSON{
|
||||
"variants": item.GenerateFortniteItemVariantChannels(),
|
||||
})
|
||||
|
||||
json["items"] = items
|
||||
json["activeVariants"] = activeVariants
|
||||
}
|
||||
|
||||
return aid.JSON{
|
||||
"items": itemIds,
|
||||
"activeVariants": []aid.JSON{},
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Loadout) Delete() {
|
||||
storage.Repo.DeleteLoadout(l.ID)
|
||||
}
|
||||
|
||||
func (l *Loadout) ToDatabase(profileId string) *storage.DB_Loadout {
|
||||
return &storage.DB_Loadout{
|
||||
ID: l.ID,
|
||||
ProfileID: profileId,
|
||||
TemplateID: l.TemplateID,
|
||||
LockerName: l.LockerName,
|
||||
BannerID: l.BannerID,
|
||||
BannerColorID: l.BannerColorID,
|
||||
CharacterID: l.CharacterID,
|
||||
PickaxeID: l.PickaxeID,
|
||||
BackpackID: l.BackpackID,
|
||||
GliderID: l.GliderID,
|
||||
DanceID: l.DanceID,
|
||||
ItemWrapID: l.ItemWrapID,
|
||||
ContrailID: l.ContrailID,
|
||||
LoadingScreenID: l.LoadingScreenID,
|
||||
MusicPackID: l.MusicPackID,
|
||||
}
|
||||
}
|
||||
|
||||
func (q *Loadout) Save() {
|
||||
storage.Repo.SaveLoadout(q.ToDatabase(q.ProfileID))
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
package person
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/ectrc/snow/storage"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
@ -108,10 +106,7 @@ func findHelper(databasePerson *storage.DB_Person) *Person {
|
|||
Profile0Profile: profile0,
|
||||
}
|
||||
|
||||
cache.Store(person.ID, &CacheEntry{
|
||||
Entry: person,
|
||||
LastAccessed: time.Now(),
|
||||
})
|
||||
cache.SavePerson(person)
|
||||
|
||||
return person
|
||||
}
|
||||
|
@ -182,6 +177,7 @@ func (p *Person) ToDatabase() *storage.DB_Person {
|
|||
Items: []storage.DB_Item{},
|
||||
Gifts: []storage.DB_Gift{},
|
||||
Quests: []storage.DB_Quest{},
|
||||
Loadouts: []storage.DB_Loadout{},
|
||||
Attributes: []storage.DB_PAttribute{},
|
||||
Revision: profile.Revision,
|
||||
}
|
||||
|
@ -206,6 +202,11 @@ func (p *Person) ToDatabase() *storage.DB_Person {
|
|||
return true
|
||||
})
|
||||
|
||||
profile.Loadouts.RangeLoadouts(func(id string, loadout *Loadout) bool {
|
||||
dbProfile.Loadouts = append(dbProfile.Loadouts, *loadout.ToDatabase(p.ID))
|
||||
return true
|
||||
})
|
||||
|
||||
dbPerson.Profiles = append(dbPerson.Profiles, dbProfile)
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ type Profile struct {
|
|||
Gifts *GiftMutex
|
||||
Quests *QuestMutex
|
||||
Attributes *AttributeMutex
|
||||
Loadouts *LoadoutMutex
|
||||
Type string
|
||||
Revision int
|
||||
Changes []interface{}
|
||||
|
@ -30,6 +31,7 @@ func NewProfile(profile string) *Profile {
|
|||
Gifts: NewGiftMutex(&storage.DB_Profile{ID: id, Type: profile}),
|
||||
Quests: NewQuestMutex(&storage.DB_Profile{ID: id, Type: profile}),
|
||||
Attributes: NewAttributeMutex(&storage.DB_Profile{ID: id, Type: profile}),
|
||||
Loadouts: NewLoadoutMutex(&storage.DB_Profile{ID: id, Type: profile}),
|
||||
Type: profile,
|
||||
Revision: 0,
|
||||
Changes: []interface{}{},
|
||||
|
@ -41,6 +43,7 @@ func FromDatabaseProfile(profile *storage.DB_Profile) *Profile {
|
|||
gifts := NewGiftMutex(profile)
|
||||
quests := NewQuestMutex(profile)
|
||||
attributes := NewAttributeMutex(profile)
|
||||
loadouts := NewLoadoutMutex(profile)
|
||||
|
||||
for _, item := range profile.Items {
|
||||
items.AddItem(FromDatabaseItem(&item))
|
||||
|
@ -54,6 +57,10 @@ func FromDatabaseProfile(profile *storage.DB_Profile) *Profile {
|
|||
quests.AddQuest(FromDatabaseQuest(&quest))
|
||||
}
|
||||
|
||||
for _, loadout := range profile.Loadouts {
|
||||
loadouts.AddLoadout(FromDatabaseLoadout(&loadout))
|
||||
}
|
||||
|
||||
for _, attribute := range profile.Attributes {
|
||||
parsed := FromDatabaseAttribute(&attribute)
|
||||
if parsed == nil {
|
||||
|
@ -71,6 +78,7 @@ func FromDatabaseProfile(profile *storage.DB_Profile) *Profile {
|
|||
Gifts: gifts,
|
||||
Quests: quests,
|
||||
Attributes: attributes,
|
||||
Loadouts: loadouts,
|
||||
Type: profile.Type,
|
||||
Revision: profile.Revision,
|
||||
Changes: []interface{}{},
|
||||
|
@ -101,6 +109,11 @@ func (p *Profile) GenerateFortniteProfileEntry() aid.JSON {
|
|||
return true
|
||||
})
|
||||
|
||||
p.Loadouts.RangeLoadouts(func(id string, loadout *Loadout) bool {
|
||||
items[id] = loadout.GenerateFortniteLoadoutEntry()
|
||||
return true
|
||||
})
|
||||
|
||||
return aid.JSON{
|
||||
"profileId": p.Type,
|
||||
"accountId": p.PersonID,
|
||||
|
@ -124,6 +137,7 @@ func (p *Profile) Snapshot() *ProfileSnapshot {
|
|||
gifts := map[string]GiftSnapshot{}
|
||||
quests := map[string]Quest{}
|
||||
attributes := map[string]Attribute{}
|
||||
loadouts := map[string]Loadout{}
|
||||
|
||||
p.Items.RangeItems(func(id string, item *Item) bool {
|
||||
items[id] = item.Snapshot()
|
||||
|
@ -145,12 +159,18 @@ func (p *Profile) Snapshot() *ProfileSnapshot {
|
|||
return true
|
||||
})
|
||||
|
||||
p.Loadouts.RangeLoadouts(func(id string, loadout *Loadout) bool {
|
||||
loadouts[id] = *loadout
|
||||
return true
|
||||
})
|
||||
|
||||
return &ProfileSnapshot{
|
||||
ID: p.ID,
|
||||
Items: items,
|
||||
Gifts: gifts,
|
||||
Quests: quests,
|
||||
Attributes: attributes,
|
||||
Loadouts: loadouts,
|
||||
Type: p.Type,
|
||||
Revision: p.Revision,
|
||||
}
|
||||
|
@ -205,6 +225,18 @@ func (p *Profile) Diff(b *ProfileSnapshot) []diff.Change {
|
|||
if change.Type == "update" && change.Path[2] == "ValueJSON" {
|
||||
p.CreateStatModifiedChange(p.Attributes.GetAttribute(change.Path[1]))
|
||||
}
|
||||
case "Loadouts":
|
||||
if change.Type == "create" && change.Path[2] == "ID" {
|
||||
p.CreateLoadoutAddedChange(p.Loadouts.GetLoadout(change.Path[1]))
|
||||
}
|
||||
|
||||
if change.Type == "delete" && change.Path[2] == "ID" {
|
||||
p.CreateLoadoutRemovedChange(change.Path[1])
|
||||
}
|
||||
|
||||
if change.Type == "update" && change.Path[2] != "ID" {
|
||||
p.CreateLoadoutChangedChange(p.Loadouts.GetLoadout(change.Path[1]), change.Path[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,6 +347,55 @@ func (p *Profile) CreateFullProfileUpdateChange() {
|
|||
}}
|
||||
}
|
||||
|
||||
func (p *Profile) CreateLoadoutAddedChange(loadout *Loadout) {
|
||||
if loadout == nil {
|
||||
fmt.Println("error getting item from profile", loadout.ID)
|
||||
return
|
||||
}
|
||||
|
||||
p.Changes = append(p.Changes, ItemAdded{
|
||||
ChangeType: "itemAdded",
|
||||
ItemId: loadout.ID,
|
||||
Item: loadout.GenerateFortniteLoadoutEntry(),
|
||||
})
|
||||
}
|
||||
|
||||
func (p *Profile) CreateLoadoutRemovedChange(loadoutId string) {
|
||||
p.Changes = append(p.Changes, ItemRemoved{
|
||||
ChangeType: "itemRemoved",
|
||||
ItemId: loadoutId,
|
||||
})
|
||||
}
|
||||
|
||||
func (p *Profile) CreateLoadoutChangedChange(loadout *Loadout, attribute string) {
|
||||
if loadout == nil {
|
||||
fmt.Println("error getting item from profile", loadout.ID)
|
||||
return
|
||||
}
|
||||
|
||||
lookup := map[string]string{
|
||||
"LockerName": "locker_name",
|
||||
"BannerID": "banner_icon_template",
|
||||
"BannerColorID": "banner_color_template",
|
||||
"CharacterID": "locker_slots_data",
|
||||
"PickaxeID": "locker_slots_data",
|
||||
"BackpackID": "locker_slots_data",
|
||||
"GliderID": "locker_slots_data",
|
||||
"DanceID": "locker_slots_data",
|
||||
"ItemWrapID": "locker_slots_data",
|
||||
"ContrailID": "locker_slots_data",
|
||||
"LoadingScreenID": "locker_slots_data",
|
||||
"MusicPackID": "locker_slots_data",
|
||||
}
|
||||
|
||||
p.Changes = append(p.Changes, ItemAttributeChanged{
|
||||
ChangeType: "itemAttributeChanged",
|
||||
ItemId: loadout.ID,
|
||||
AttributeName: lookup[attribute],
|
||||
AttributeValue: loadout.GetAttribute(lookup[attribute]),
|
||||
})
|
||||
}
|
||||
|
||||
func (p *Profile) ClearProfileChanges() {
|
||||
p.Changes = []interface{}{}
|
||||
}
|
|
@ -15,6 +15,7 @@ type ProfileSnapshot struct {
|
|||
Gifts map[string]GiftSnapshot
|
||||
Quests map[string]Quest
|
||||
Attributes map[string]Attribute
|
||||
Loadouts map[string]Loadout
|
||||
Revision int
|
||||
Type string
|
||||
}
|
||||
|
|
|
@ -19,11 +19,12 @@ func NewItemMutex(profile *storage.DB_Profile) *ItemMutex {
|
|||
}
|
||||
}
|
||||
|
||||
func (m *ItemMutex) AddItem(item *Item) {
|
||||
func (m *ItemMutex) AddItem(item *Item) *Item {
|
||||
item.ProfileType = m.ProfileType
|
||||
item.ProfileID = m.ProfileID
|
||||
m.Store(item.ID, item)
|
||||
storage.Repo.SaveItem(item.ToDatabase(m.ProfileID))
|
||||
// storage.Repo.SaveItem(item.ToDatabase(m.ProfileID))
|
||||
return item
|
||||
}
|
||||
|
||||
func (m *ItemMutex) DeleteItem(id string) {
|
||||
|
@ -89,10 +90,11 @@ func NewGiftMutex(profile *storage.DB_Profile) *GiftMutex {
|
|||
}
|
||||
}
|
||||
|
||||
func (m *GiftMutex) AddGift(gift *Gift) {
|
||||
func (m *GiftMutex) AddGift(gift *Gift) *Gift {
|
||||
gift.ProfileID = m.ProfileID
|
||||
m.Store(gift.ID, gift)
|
||||
storage.Repo.SaveGift(gift.ToDatabase(m.ProfileID))
|
||||
// storage.Repo.SaveGift(gift.ToDatabase(m.ProfileID))
|
||||
return gift
|
||||
}
|
||||
|
||||
func (m *GiftMutex) DeleteGift(id string) {
|
||||
|
@ -137,10 +139,11 @@ func NewQuestMutex(profile *storage.DB_Profile) *QuestMutex {
|
|||
}
|
||||
}
|
||||
|
||||
func (m *QuestMutex) AddQuest(quest *Quest) {
|
||||
func (m *QuestMutex) AddQuest(quest *Quest) *Quest {
|
||||
quest.ProfileID = m.ProfileID
|
||||
m.Store(quest.ID, quest)
|
||||
storage.Repo.SaveQuest(quest.ToDatabase(m.ProfileID))
|
||||
// storage.Repo.SaveQuest(quest.ToDatabase(m.ProfileID))
|
||||
return quest
|
||||
}
|
||||
|
||||
func (m *QuestMutex) DeleteQuest(id string) {
|
||||
|
@ -184,10 +187,11 @@ func NewAttributeMutex(profile *storage.DB_Profile) *AttributeMutex {
|
|||
}
|
||||
}
|
||||
|
||||
func (m *AttributeMutex) AddAttribute(attribute *Attribute) {
|
||||
func (m *AttributeMutex) AddAttribute(attribute *Attribute) *Attribute {
|
||||
attribute.ProfileID = m.ProfileID
|
||||
m.Store(attribute.ID, attribute)
|
||||
storage.Repo.SaveAttribute(attribute.ToDatabase(m.ProfileID))
|
||||
// storage.Repo.SaveAttribute(attribute.ToDatabase(m.ProfileID))
|
||||
return attribute
|
||||
}
|
||||
|
||||
func (m *AttributeMutex) DeleteAttribute(id string) {
|
||||
|
@ -233,3 +237,72 @@ func (m *AttributeMutex) Count() int {
|
|||
})
|
||||
return count
|
||||
}
|
||||
|
||||
type LoadoutMutex struct {
|
||||
sync.Map
|
||||
ProfileType string
|
||||
ProfileID string
|
||||
}
|
||||
|
||||
func NewLoadoutMutex(profile *storage.DB_Profile) *LoadoutMutex {
|
||||
return &LoadoutMutex{
|
||||
ProfileID: profile.ID,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *LoadoutMutex) AddLoadout(loadout *Loadout) *Loadout {
|
||||
loadout.ProfileID = m.ProfileID
|
||||
m.Store(loadout.ID, loadout)
|
||||
// storage.Repo.SaveLoadout(loadout.ToDatabase(m.ProfileID))
|
||||
return loadout
|
||||
}
|
||||
|
||||
func (m *LoadoutMutex) DeleteItem(id string) {
|
||||
loadout := m.GetLoadout(id)
|
||||
if loadout == nil {
|
||||
return
|
||||
}
|
||||
|
||||
loadout.Delete()
|
||||
m.Delete(id)
|
||||
storage.Repo.DeleteItem(id)
|
||||
}
|
||||
|
||||
func (m *LoadoutMutex) GetLoadout(id string) *Loadout {
|
||||
loadout, ok := m.Load(id)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return loadout.(*Loadout)
|
||||
}
|
||||
|
||||
func (m *LoadoutMutex) GetLoadoutByName(name string) *Loadout {
|
||||
var loadout *Loadout
|
||||
|
||||
m.Range(func(key, value interface{}) bool {
|
||||
if value.(*Loadout).LockerName == name {
|
||||
loadout = value.(*Loadout)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
return loadout
|
||||
}
|
||||
|
||||
func (m *LoadoutMutex) RangeLoadouts(f func(key string, value *Loadout) bool) {
|
||||
m.Range(func(key, value interface{}) bool {
|
||||
return f(key.(string), value.(*Loadout))
|
||||
})
|
||||
}
|
||||
|
||||
func (m *LoadoutMutex) Count() int {
|
||||
count := 0
|
||||
m.Range(func(key, value interface{}) bool {
|
||||
count++
|
||||
return true
|
||||
})
|
||||
return count
|
||||
}
|
|
@ -59,7 +59,8 @@ user.CommonCoreProfile.Diff(snapshot)
|
|||
|
||||
- **_Chapter 1 Season 2_** `Fortnite+Release-2.5-CL-3889387-Windows` I started with this build of the game as it requires more work to get working, this means snow can support _most_ versions of the game.
|
||||
- **_Chapter 1 Season 5_** `Fortnite+Release-5.41-CL-4363240-Windows` This build was used to make sure challenges, variants and lobby backgrounds work.
|
||||
- **_Chapter 1 Season 8_** `Fortnite+Release-8.51-CL-6165369-Windows` Fixed the invisible player bugs and other specific issues.
|
||||
- **_Chapter 1 Season 8_** `Fortnite+Release-8.51-CL-6165369-Windows` Fixed the invisible player bug caused by invalid account responses. Also fixed the issue with the item shop spamming the api.
|
||||
- **_Chapter 3 Season 1_** `Fortnite+Release-19.10-CL-Unknown-Windows` This is a very new build of fortnite that introfuces alot of different methods e.g. locker data is now stored as an item. Every MCP action is now fully working and tested. You need to start using easy anticheat otherwise this will not work.
|
||||
|
||||
### Broken
|
||||
|
||||
|
|
6304
storage/mem/cosmetics.json
Normal file
6304
storage/mem/cosmetics.json
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -4,6 +4,7 @@ import (
|
|||
"github.com/ectrc/snow/aid"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
type PostgresStorage struct {
|
||||
|
@ -11,7 +12,9 @@ type PostgresStorage struct {
|
|||
}
|
||||
|
||||
func NewPostgresStorage() *PostgresStorage {
|
||||
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),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -34,6 +37,7 @@ func (s *PostgresStorage) MigrateAll() {
|
|||
s.Migrate(&DB_Loot{}, "Loot")
|
||||
s.Migrate(&DB_VariantChannel{}, "Variants")
|
||||
s.Migrate(&DB_PAttribute{}, "Attributes")
|
||||
s.Migrate(&DB_Loadout{}, "Loadouts")
|
||||
}
|
||||
|
||||
func (s *PostgresStorage) DropTables() {
|
||||
|
@ -50,6 +54,8 @@ func (s *PostgresStorage) GetPerson(personId string) *DB_Person {
|
|||
Preload("Profiles.Items").
|
||||
Preload("Profiles.Gifts").
|
||||
Preload("Profiles.Quests").
|
||||
Preload("Profiles.Loadouts").
|
||||
Where("id = ?", personId).
|
||||
Find(&dbPerson)
|
||||
|
||||
if dbPerson.ID == "" {
|
||||
|
@ -62,13 +68,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").
|
||||
// Preload("Profiles.Items.Variants").
|
||||
// Preload("Profiles.Gifts.Loot").
|
||||
// Preload("Profiles.Attributes").
|
||||
// Preload("Profiles.Items").
|
||||
// Preload("Profiles.Gifts").
|
||||
// Preload("Profiles.Quests").
|
||||
// Preload("Profiles.Loadouts").
|
||||
Where("display_name = ?", displayName).
|
||||
Find(&dbPerson)
|
||||
|
||||
|
@ -90,6 +97,7 @@ func (s *PostgresStorage) GetAllPersons() []*DB_Person {
|
|||
Preload("Profiles.Items").
|
||||
Preload("Profiles.Gifts").
|
||||
Preload("Profiles.Quests").
|
||||
Preload("Profiles.Loadouts").
|
||||
Find(&dbPersons)
|
||||
|
||||
return dbPersons
|
||||
|
@ -158,3 +166,11 @@ func (s *PostgresStorage) SaveAttribute(attribute *DB_PAttribute) {
|
|||
func (s *PostgresStorage) DeleteAttribute(attributeId string) {
|
||||
s.Postgres.Delete(&DB_PAttribute{}, "id = ?", attributeId)
|
||||
}
|
||||
|
||||
func (s *PostgresStorage) SaveLoadout(loadout *DB_Loadout) {
|
||||
s.Postgres.Save(loadout)
|
||||
}
|
||||
|
||||
func (s *PostgresStorage) DeleteLoadout(loadoutId string) {
|
||||
s.Postgres.Delete(&DB_Loadout{}, "id = ?", loadoutId)
|
||||
}
|
|
@ -32,6 +32,9 @@ type Storage interface {
|
|||
|
||||
SaveAttribute(attribute *DB_PAttribute)
|
||||
DeleteAttribute(attributeId string)
|
||||
|
||||
SaveLoadout(loadout *DB_Loadout)
|
||||
DeleteLoadout(loadoutId string)
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
|
@ -125,3 +128,11 @@ func (r *Repository) SaveAttribute(attribute *DB_PAttribute) {
|
|||
func (r *Repository) DeleteAttribute(attributeId string) {
|
||||
r.Storage.DeleteAttribute(attributeId)
|
||||
}
|
||||
|
||||
func (r *Repository) SaveLoadout(loadout *DB_Loadout) {
|
||||
r.Storage.SaveLoadout(loadout)
|
||||
}
|
||||
|
||||
func (r *Repository) DeleteLoadout(loadoutId string) {
|
||||
r.Storage.DeleteLoadout(loadoutId)
|
||||
}
|
|
@ -24,6 +24,7 @@ type DB_Profile struct {
|
|||
Gifts []DB_Gift `gorm:"foreignkey:ProfileID"`
|
||||
Quests []DB_Quest `gorm:"foreignkey:ProfileID"`
|
||||
Attributes []DB_PAttribute `gorm:"foreignkey:ProfileID"`
|
||||
Loadouts []DB_Loadout `gorm:"foreignkey:ProfileID"`
|
||||
Type string
|
||||
Revision int
|
||||
}
|
||||
|
@ -44,6 +45,28 @@ func (DB_PAttribute) TableName() string {
|
|||
return "Attributes"
|
||||
}
|
||||
|
||||
type DB_Loadout struct {
|
||||
ID string `gorm:"primary_key"`
|
||||
ProfileID string
|
||||
TemplateID string
|
||||
LockerName string
|
||||
BannerID string
|
||||
BannerColorID string
|
||||
CharacterID string
|
||||
PickaxeID string
|
||||
BackpackID string
|
||||
GliderID string
|
||||
DanceID pq.StringArray `gorm:"type:text[]"`
|
||||
ItemWrapID pq.StringArray `gorm:"type:text[]"`
|
||||
ContrailID string
|
||||
LoadingScreenID string
|
||||
MusicPackID string
|
||||
}
|
||||
|
||||
func (DB_Loadout) TableName() string {
|
||||
return "Loadouts"
|
||||
}
|
||||
|
||||
type DB_Item struct {
|
||||
ID string `gorm:"primary_key"`
|
||||
ProfileID string
|
||||
|
|
Loading…
Reference in New Issue
Block a user