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 (
|
var (
|
||||||
oatuhTokenGrantTypes = map[string]func(c *fiber.Ctx, body *OAuthTokenBody) error{
|
oauthTokenGrantTypes = map[string]func(c *fiber.Ctx, body *OAuthTokenBody) error{
|
||||||
"client_credentials": PostOAuthTokenClientCredentials,
|
"client_credentials": PostOAuthTokenClientCredentials,
|
||||||
"password": PostOAuthTokenPassword,
|
"password": PostOAuthTokenPassword,
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ func PostOAuthToken(c *fiber.Ctx) error {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(aid.ErrorBadRequest("Invalid Request Body"))
|
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)
|
return action(c, &body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/ectrc/snow/aid"
|
"github.com/ectrc/snow/aid"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
@ -26,7 +28,7 @@ func GetFortniteReceipts(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMatchmakingSession(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 {
|
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 {
|
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{
|
return c.Status(fiber.StatusOK).JSON(aid.JSON{
|
||||||
"battlepassaboutmessages": aid.JSON{
|
"battlepassaboutmessages": aid.JSON{
|
||||||
|
@ -77,14 +95,14 @@ func GetContentPages(c *fiber.Ctx) error {
|
||||||
},
|
},
|
||||||
"dynamicbackgrounds": aid.JSON{
|
"dynamicbackgrounds": aid.JSON{
|
||||||
"backgrounds": aid.JSON{"backgrounds": []aid.JSON{
|
"backgrounds": aid.JSON{"backgrounds": []aid.JSON{
|
||||||
// {
|
{
|
||||||
// "key": "lobby",
|
"key": "lobby",
|
||||||
// "stage": "season"+seasonString,
|
"stage": "season" + seasonString,
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// "key": "vault",
|
"key": "vault",
|
||||||
// "stage": "season"+seasonString,
|
"stage": "season" + seasonString,
|
||||||
// },
|
},
|
||||||
}},
|
}},
|
||||||
"lastModified": "0000-00-00T00:00:00.000Z",
|
"lastModified": "0000-00-00T00:00:00.000Z",
|
||||||
},
|
},
|
||||||
|
|
|
@ -29,28 +29,35 @@ func PostProfileAction(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
profile := person.GetProfileFromType(c.Query("profileId"))
|
profile := person.GetProfileFromType(c.Query("profileId"))
|
||||||
defer profile.ClearProfileChanges()
|
if action, ok := profileActions[c.Params("action")]; ok && profile != nil {
|
||||||
|
defer profile.ClearProfileChanges()
|
||||||
before := profile.Snapshot()
|
before := profile.Snapshot()
|
||||||
if action, ok := profileActions[c.Params("action")]; ok {
|
|
||||||
if err := action(c, person, profile); err != nil {
|
if err := action(c, person, profile); err != nil {
|
||||||
return c.Status(400).JSON(aid.ErrorBadRequest(err.Error()))
|
return c.Status(400).JSON(aid.ErrorBadRequest(err.Error()))
|
||||||
}
|
}
|
||||||
|
profile.Diff(before)
|
||||||
}
|
}
|
||||||
profile.Diff(before)
|
|
||||||
|
|
||||||
revision, _ := strconv.Atoi(c.Query("rvn"))
|
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 = profile.Revision
|
||||||
}
|
}
|
||||||
revision++
|
revision++
|
||||||
|
|
||||||
|
changes := []interface{}{}
|
||||||
|
if profile != nil {
|
||||||
|
changes = profile.Changes
|
||||||
|
}
|
||||||
|
|
||||||
return c.Status(200).JSON(aid.JSON{
|
return c.Status(200).JSON(aid.JSON{
|
||||||
"profileId": profile.Type,
|
"profileId": c.Query("profileId"),
|
||||||
"profileRevision": revision,
|
"profileRevision": revision,
|
||||||
"profileCommandRevision": revision,
|
"profileCommandRevision": revision,
|
||||||
"profileChangesBaseRevision": revision - 1,
|
"profileChangesBaseRevision": revision - 1,
|
||||||
"profileChanges": profile.Changes,
|
"profileChanges": changes,
|
||||||
"multiUpdate": []aid.JSON{},
|
"multiUpdate": []aid.JSON{},
|
||||||
"notifications": []aid.JSON{},
|
"notifications": []aid.JSON{},
|
||||||
"responseVersion": 1,
|
"responseVersion": 1,
|
||||||
|
|
|
@ -1,12 +1,119 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
|
|
||||||
"github.com/ectrc/snow/aid"
|
"github.com/ectrc/snow/aid"
|
||||||
"github.com/gofiber/fiber/v2"
|
"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 {
|
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 {
|
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.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 {
|
func GetUserStorageFiles(c *fiber.Ctx) error {
|
||||||
|
|
8
main.go
8
main.go
|
@ -45,6 +45,14 @@ func main() {
|
||||||
r.Use(aid.FiberCors())
|
r.Use(aid.FiberCors())
|
||||||
|
|
||||||
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("/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 := r.Group("/account/api")
|
||||||
account.Get("/public/account", handlers.GetPublicAccounts)
|
account.Get("/public/account", handlers.GetPublicAccounts)
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package person
|
package person
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/ectrc/snow/aid"
|
"github.com/ectrc/snow/aid"
|
||||||
|
"github.com/ectrc/snow/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -25,7 +27,7 @@ func NewFortnitePerson(displayName string, key string) *Person {
|
||||||
person.DisplayName = displayName
|
person.DisplayName = displayName
|
||||||
person.AccessKey = key
|
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 {
|
for _, item := range defaultAthenaItems {
|
||||||
person.AthenaProfile.Items.AddItem(NewItem(item, 1))
|
person.AthenaProfile.Items.AddItem(NewItem(item, 1))
|
||||||
|
@ -34,77 +36,91 @@ func NewFortnitePerson(displayName string, key string) *Person {
|
||||||
for _, item := range defaultCommonCoreItems {
|
for _, item := range defaultCommonCoreItems {
|
||||||
if item == "HomebaseBannerIcon:StandardBanner" {
|
if item == "HomebaseBannerIcon:StandardBanner" {
|
||||||
for i := 1; i < 32; i++ {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if item == "HomebaseBannerColor:DefaultColor" {
|
if item == "HomebaseBannerColor:DefaultColor" {
|
||||||
for i := 1; i < 22; i++ {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if item == "Currency:MtxPurchased" {
|
if item == "Currency:MtxPurchased" {
|
||||||
person.CommonCoreProfile.Items.AddItem(NewItem(item, 0))
|
person.CommonCoreProfile.Items.AddItem(NewItem(item, 0)).Save()
|
||||||
continue
|
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("mfa_reward_claimed", true)).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("rested_xp_overflow", 0))
|
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("rested_xp_overflow", 0)).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("lifetime_wins", 0))
|
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("lifetime_wins", 0)).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("party_assist_quest", ""))
|
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("party_assist_quest", "")).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("quest_manager", aid.JSON{}))
|
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("quest_manager", aid.JSON{})).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("inventory_limit_bonus", 0))
|
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("inventory_limit_bonus", 0)).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("daily_rewards", []aid.JSON{}))
|
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("daily_rewards", []aid.JSON{})).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("competitive_identity", aid.JSON{}))
|
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("competitive_identity", aid.JSON{})).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_update", 0))
|
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_update", 0)).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_num", aid.Config.Fortnite.Season))
|
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_num", aid.Config.Fortnite.Season)).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("permissions", []aid.JSON{}))
|
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("accountLevel", 1)).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("last_applied_loadout", ""))
|
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("level", 1)).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("active_loadout_index", 0))
|
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("book_purchased", false)).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("level", 1))
|
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("book_level", 1)).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("xp", 0))
|
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("book_xp", 0)).Save()
|
||||||
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))
|
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("book_level", 1))
|
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_backpack", "")).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("book_xp", 0))
|
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.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("mfa_enabled", true)).Save()
|
||||||
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_backpack", ""))
|
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("mtx_affiliate", "")).Save()
|
||||||
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("mtx_purchase_history", aid.JSON{
|
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("mtx_purchase_history", aid.JSON{
|
||||||
"refundsUsed": 0,
|
"refundsUsed": 0,
|
||||||
"refundCredits": 3,
|
"refundCredits": 3,
|
||||||
"purchases": []any{},
|
"purchases": []any{},
|
||||||
}))
|
})).Save()
|
||||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("current_mtx_platform", "EpicPC"))
|
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("current_mtx_platform", "EpicPC")).Save()
|
||||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("allowed_to_receive_gifts", true))
|
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("allowed_to_receive_gifts", true)).Save()
|
||||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("allowed_to_send_gifts", true))
|
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("allowed_to_send_gifts", true)).Save()
|
||||||
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("gift_history", aid.JSON{}))
|
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()
|
person.Save()
|
||||||
|
|
||||||
|
|
|
@ -70,21 +70,12 @@ func FromDatabaseLoot(item *storage.DB_Loot) *Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Item) GenerateFortniteItemEntry() aid.JSON {
|
func (i *Item) GenerateFortniteItemEntry() aid.JSON {
|
||||||
variants := []aid.JSON{}
|
|
||||||
attributes := aid.JSON{
|
attributes := aid.JSON{
|
||||||
"variants": variants,
|
"variants": i.GenerateFortniteItemVariantChannels(),
|
||||||
"favorite": i.Favorite,
|
"favorite": i.Favorite,
|
||||||
"item_seen": i.HasSeen,
|
"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" {
|
if i.TemplateID == "Currency:MtxPurchased" {
|
||||||
attributes = aid.JSON{
|
attributes = aid.JSON{
|
||||||
"platform": "Shared",
|
"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{} {
|
func (i *Item) GetAttribute(attribute string) interface{} {
|
||||||
switch attribute {
|
switch attribute {
|
||||||
case "Favorite":
|
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
|
package person
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ectrc/snow/storage"
|
"github.com/ectrc/snow/storage"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
@ -108,10 +106,7 @@ func findHelper(databasePerson *storage.DB_Person) *Person {
|
||||||
Profile0Profile: profile0,
|
Profile0Profile: profile0,
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.Store(person.ID, &CacheEntry{
|
cache.SavePerson(person)
|
||||||
Entry: person,
|
|
||||||
LastAccessed: time.Now(),
|
|
||||||
})
|
|
||||||
|
|
||||||
return person
|
return person
|
||||||
}
|
}
|
||||||
|
@ -182,6 +177,7 @@ func (p *Person) ToDatabase() *storage.DB_Person {
|
||||||
Items: []storage.DB_Item{},
|
Items: []storage.DB_Item{},
|
||||||
Gifts: []storage.DB_Gift{},
|
Gifts: []storage.DB_Gift{},
|
||||||
Quests: []storage.DB_Quest{},
|
Quests: []storage.DB_Quest{},
|
||||||
|
Loadouts: []storage.DB_Loadout{},
|
||||||
Attributes: []storage.DB_PAttribute{},
|
Attributes: []storage.DB_PAttribute{},
|
||||||
Revision: profile.Revision,
|
Revision: profile.Revision,
|
||||||
}
|
}
|
||||||
|
@ -206,6 +202,11 @@ func (p *Person) ToDatabase() *storage.DB_Person {
|
||||||
return true
|
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)
|
dbPerson.Profiles = append(dbPerson.Profiles, dbProfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,12 @@ type Profile struct {
|
||||||
PersonID string
|
PersonID string
|
||||||
Items *ItemMutex
|
Items *ItemMutex
|
||||||
Gifts *GiftMutex
|
Gifts *GiftMutex
|
||||||
Quests *QuestMutex
|
Quests *QuestMutex
|
||||||
Attributes *AttributeMutex
|
Attributes *AttributeMutex
|
||||||
Type string
|
Loadouts *LoadoutMutex
|
||||||
Revision int
|
Type string
|
||||||
Changes []interface{}
|
Revision int
|
||||||
|
Changes []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProfile(profile string) *Profile {
|
func NewProfile(profile string) *Profile {
|
||||||
|
@ -28,8 +29,9 @@ func NewProfile(profile string) *Profile {
|
||||||
PersonID: "",
|
PersonID: "",
|
||||||
Items: NewItemMutex(&storage.DB_Profile{ID: id, Type: profile}),
|
Items: NewItemMutex(&storage.DB_Profile{ID: id, Type: profile}),
|
||||||
Gifts: NewGiftMutex(&storage.DB_Profile{ID: id, Type: profile}),
|
Gifts: NewGiftMutex(&storage.DB_Profile{ID: id, Type: profile}),
|
||||||
Quests: NewQuestMutex(&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}),
|
Attributes: NewAttributeMutex(&storage.DB_Profile{ID: id, Type: profile}),
|
||||||
|
Loadouts: NewLoadoutMutex(&storage.DB_Profile{ID: id, Type: profile}),
|
||||||
Type: profile,
|
Type: profile,
|
||||||
Revision: 0,
|
Revision: 0,
|
||||||
Changes: []interface{}{},
|
Changes: []interface{}{},
|
||||||
|
@ -41,6 +43,7 @@ func FromDatabaseProfile(profile *storage.DB_Profile) *Profile {
|
||||||
gifts := NewGiftMutex(profile)
|
gifts := NewGiftMutex(profile)
|
||||||
quests := NewQuestMutex(profile)
|
quests := NewQuestMutex(profile)
|
||||||
attributes := NewAttributeMutex(profile)
|
attributes := NewAttributeMutex(profile)
|
||||||
|
loadouts := NewLoadoutMutex(profile)
|
||||||
|
|
||||||
for _, item := range profile.Items {
|
for _, item := range profile.Items {
|
||||||
items.AddItem(FromDatabaseItem(&item))
|
items.AddItem(FromDatabaseItem(&item))
|
||||||
|
@ -54,6 +57,10 @@ func FromDatabaseProfile(profile *storage.DB_Profile) *Profile {
|
||||||
quests.AddQuest(FromDatabaseQuest(&quest))
|
quests.AddQuest(FromDatabaseQuest(&quest))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, loadout := range profile.Loadouts {
|
||||||
|
loadouts.AddLoadout(FromDatabaseLoadout(&loadout))
|
||||||
|
}
|
||||||
|
|
||||||
for _, attribute := range profile.Attributes {
|
for _, attribute := range profile.Attributes {
|
||||||
parsed := FromDatabaseAttribute(&attribute)
|
parsed := FromDatabaseAttribute(&attribute)
|
||||||
if parsed == nil {
|
if parsed == nil {
|
||||||
|
@ -71,6 +78,7 @@ func FromDatabaseProfile(profile *storage.DB_Profile) *Profile {
|
||||||
Gifts: gifts,
|
Gifts: gifts,
|
||||||
Quests: quests,
|
Quests: quests,
|
||||||
Attributes: attributes,
|
Attributes: attributes,
|
||||||
|
Loadouts: loadouts,
|
||||||
Type: profile.Type,
|
Type: profile.Type,
|
||||||
Revision: profile.Revision,
|
Revision: profile.Revision,
|
||||||
Changes: []interface{}{},
|
Changes: []interface{}{},
|
||||||
|
@ -101,6 +109,11 @@ func (p *Profile) GenerateFortniteProfileEntry() aid.JSON {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
p.Loadouts.RangeLoadouts(func(id string, loadout *Loadout) bool {
|
||||||
|
items[id] = loadout.GenerateFortniteLoadoutEntry()
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
return aid.JSON{
|
return aid.JSON{
|
||||||
"profileId": p.Type,
|
"profileId": p.Type,
|
||||||
"accountId": p.PersonID,
|
"accountId": p.PersonID,
|
||||||
|
@ -124,6 +137,7 @@ func (p *Profile) Snapshot() *ProfileSnapshot {
|
||||||
gifts := map[string]GiftSnapshot{}
|
gifts := map[string]GiftSnapshot{}
|
||||||
quests := map[string]Quest{}
|
quests := map[string]Quest{}
|
||||||
attributes := map[string]Attribute{}
|
attributes := map[string]Attribute{}
|
||||||
|
loadouts := map[string]Loadout{}
|
||||||
|
|
||||||
p.Items.RangeItems(func(id string, item *Item) bool {
|
p.Items.RangeItems(func(id string, item *Item) bool {
|
||||||
items[id] = item.Snapshot()
|
items[id] = item.Snapshot()
|
||||||
|
@ -145,12 +159,18 @@ func (p *Profile) Snapshot() *ProfileSnapshot {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
p.Loadouts.RangeLoadouts(func(id string, loadout *Loadout) bool {
|
||||||
|
loadouts[id] = *loadout
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
return &ProfileSnapshot{
|
return &ProfileSnapshot{
|
||||||
ID: p.ID,
|
ID: p.ID,
|
||||||
Items: items,
|
Items: items,
|
||||||
Gifts: gifts,
|
Gifts: gifts,
|
||||||
Quests: quests,
|
Quests: quests,
|
||||||
Attributes: attributes,
|
Attributes: attributes,
|
||||||
|
Loadouts: loadouts,
|
||||||
Type: p.Type,
|
Type: p.Type,
|
||||||
Revision: p.Revision,
|
Revision: p.Revision,
|
||||||
}
|
}
|
||||||
|
@ -205,6 +225,18 @@ func (p *Profile) Diff(b *ProfileSnapshot) []diff.Change {
|
||||||
if change.Type == "update" && change.Path[2] == "ValueJSON" {
|
if change.Type == "update" && change.Path[2] == "ValueJSON" {
|
||||||
p.CreateStatModifiedChange(p.Attributes.GetAttribute(change.Path[1]))
|
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() {
|
func (p *Profile) ClearProfileChanges() {
|
||||||
p.Changes = []interface{}{}
|
p.Changes = []interface{}{}
|
||||||
}
|
}
|
|
@ -15,6 +15,7 @@ type ProfileSnapshot struct {
|
||||||
Gifts map[string]GiftSnapshot
|
Gifts map[string]GiftSnapshot
|
||||||
Quests map[string]Quest
|
Quests map[string]Quest
|
||||||
Attributes map[string]Attribute
|
Attributes map[string]Attribute
|
||||||
|
Loadouts map[string]Loadout
|
||||||
Revision int
|
Revision int
|
||||||
Type string
|
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.ProfileType = m.ProfileType
|
||||||
item.ProfileID = m.ProfileID
|
item.ProfileID = m.ProfileID
|
||||||
m.Store(item.ID, item)
|
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) {
|
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
|
gift.ProfileID = m.ProfileID
|
||||||
m.Store(gift.ID, gift)
|
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) {
|
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
|
quest.ProfileID = m.ProfileID
|
||||||
m.Store(quest.ID, quest)
|
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) {
|
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
|
attribute.ProfileID = m.ProfileID
|
||||||
m.Store(attribute.ID, attribute)
|
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) {
|
func (m *AttributeMutex) DeleteAttribute(id string) {
|
||||||
|
@ -232,4 +236,73 @@ func (m *AttributeMutex) Count() int {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
return count
|
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 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 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
|
### 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"
|
"github.com/ectrc/snow/aid"
|
||||||
"gorm.io/driver/postgres"
|
"gorm.io/driver/postgres"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PostgresStorage struct {
|
type PostgresStorage struct {
|
||||||
|
@ -11,7 +12,9 @@ type PostgresStorage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPostgresStorage() *PostgresStorage {
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -34,6 +37,7 @@ func (s *PostgresStorage) MigrateAll() {
|
||||||
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() {
|
||||||
|
@ -50,6 +54,8 @@ func (s *PostgresStorage) GetPerson(personId string) *DB_Person {
|
||||||
Preload("Profiles.Items").
|
Preload("Profiles.Items").
|
||||||
Preload("Profiles.Gifts").
|
Preload("Profiles.Gifts").
|
||||||
Preload("Profiles.Quests").
|
Preload("Profiles.Quests").
|
||||||
|
Preload("Profiles.Loadouts").
|
||||||
|
Where("id = ?", personId).
|
||||||
Find(&dbPerson)
|
Find(&dbPerson)
|
||||||
|
|
||||||
if dbPerson.ID == "" {
|
if dbPerson.ID == "" {
|
||||||
|
@ -62,13 +68,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.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("display_name = ?", displayName).
|
Where("display_name = ?", displayName).
|
||||||
Find(&dbPerson)
|
Find(&dbPerson)
|
||||||
|
|
||||||
|
@ -90,6 +97,7 @@ func (s *PostgresStorage) GetAllPersons() []*DB_Person {
|
||||||
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
|
||||||
|
@ -158,3 +166,11 @@ func (s *PostgresStorage) SaveAttribute(attribute *DB_PAttribute) {
|
||||||
func (s *PostgresStorage) DeleteAttribute(attributeId string) {
|
func (s *PostgresStorage) DeleteAttribute(attributeId string) {
|
||||||
s.Postgres.Delete(&DB_PAttribute{}, "id = ?", attributeId)
|
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)
|
SaveAttribute(attribute *DB_PAttribute)
|
||||||
DeleteAttribute(attributeId string)
|
DeleteAttribute(attributeId string)
|
||||||
|
|
||||||
|
SaveLoadout(loadout *DB_Loadout)
|
||||||
|
DeleteLoadout(loadoutId string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Repository struct {
|
type Repository struct {
|
||||||
|
@ -124,4 +127,12 @@ func (r *Repository) SaveAttribute(attribute *DB_PAttribute) {
|
||||||
|
|
||||||
func (r *Repository) DeleteAttribute(attributeId string) {
|
func (r *Repository) DeleteAttribute(attributeId string) {
|
||||||
r.Storage.DeleteAttribute(attributeId)
|
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"`
|
Gifts []DB_Gift `gorm:"foreignkey:ProfileID"`
|
||||||
Quests []DB_Quest `gorm:"foreignkey:ProfileID"`
|
Quests []DB_Quest `gorm:"foreignkey:ProfileID"`
|
||||||
Attributes []DB_PAttribute `gorm:"foreignkey:ProfileID"`
|
Attributes []DB_PAttribute `gorm:"foreignkey:ProfileID"`
|
||||||
|
Loadouts []DB_Loadout `gorm:"foreignkey:ProfileID"`
|
||||||
Type string
|
Type string
|
||||||
Revision int
|
Revision int
|
||||||
}
|
}
|
||||||
|
@ -44,6 +45,28 @@ func (DB_PAttribute) TableName() string {
|
||||||
return "Attributes"
|
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 {
|
type DB_Item struct {
|
||||||
ID string `gorm:"primary_key"`
|
ID string `gorm:"primary_key"`
|
||||||
ProfileID string
|
ProfileID string
|
||||||
|
|
Loading…
Reference in New Issue
Block a user