Clients/Client2018/content/internal/AppShell/Modules/Shell/GameData.lua

861 lines
26 KiB
Lua

--[[
// GameData.lua
// Fetches data for a game to be used to fill out
// the details of that game
]]
local XboxUpdateBadgeEndpoints = settings():GetFFlag("XboxUpdateBadgeEndpoints")
local CoreGui = game:GetService("CoreGui")
local GuiRoot = CoreGui:FindFirstChild("RobloxGui")
local Modules = GuiRoot:FindFirstChild("Modules")
local ShellModules = Modules:FindFirstChild("Shell")
local Http = require(ShellModules:FindFirstChild('Http'))
local Utility = require(ShellModules:FindFirstChild('Utility'))
local ConvertMyPlaceNameInXboxAppFlag = Utility.IsFastFlagEnabled("ConvertMyPlaceNameInXboxApp")
local EventHub = require(ShellModules:FindFirstChild('EventHub'))
local CreateCacheData = require(ShellModules:FindFirstChild('CachedData'))
local GlobalSettings = require(ShellModules:FindFirstChild('GlobalSettings'))
local XboxAppState = require(ShellModules:FindFirstChild('AppState'))
local ThirdPartyUserService = nil
pcall(function()ThirdPartyUserService = game:GetService('ThirdPartyUserService') end)
local GameData = {}
local gameCreatorCache = {}
function GameData:GetGameCreatorAsync(placeId)
if placeId then
if not gameCreatorCache[placeId] then
local gameDataByPlaceId = self:GetGameDataAsync(placeId)
gameCreatorCache[placeId] = gameDataByPlaceId:GetCreatorName()
end
return gameCreatorCache[placeId]
end
end
function GameData:ExtractGeneratedUsername(gameName)
local tempUsername = string.match(gameName, "^([0-9a-fA-F]+)'s Place$")
if tempUsername and #tempUsername == 32 then
return tempUsername
end
end
-- Fix places that have been made with incorrect temporary usernames
-- creatorName is optional and must be used when querying a game that is
-- not the current user's creation
function GameData:GetFilteredGameName(gameName, creatorName)
if ConvertMyPlaceNameInXboxAppFlag and gameName and type(gameName) == 'string' then
local tempUsername = self:ExtractGeneratedUsername(gameName)
if tempUsername then
local realUsername = creatorName or XboxAppState.store:getState().RobloxUser.robloxName
if realUsername then
local newGameName = string.gsub(gameName, tempUsername, realUsername, 1)
if newGameName then
return newGameName
end
end
end
end
return gameName
end
function GameData:GetGameDataAsync(placeId)
local this = {}
local result = Http.GetGameDetailsAsync(placeId)
if not result then
Utility.DebugLog("GameData:GetGameDataAsync() failed to get web response for placeId "..tostring(placeId))
result = {}
end
this.Data = result
--[[ Public API ]]--
function this:GetCreatorName()
return self.Data["Builder"] or ""
end
function this:GetDescription()
return self.Data["Description"] or ""
end
function this:GetIsFavoritedByUser()
return self.Data["IsFavoritedByUser"] or false
end
function this:GetLastUpdated()
return self.Data["Updated"] or ""
end
function this:GetCreationDate()
return self.Data["Created"] or ""
end
function this:GetMaxPlayers()
return self.Data["MaxPlayers"] or 0
end
function this:GetOverridesDefaultAvatar()
return self.Data["OverridesDefaultAvatar"] or false
end
--IsExperimental means not Filtering Enabled
function this:GetIsExperimental()
return self.Data["IsExperimental"] or false
end
function this:GetCreatorUserId()
return self.Data["BuilderId"]
end
--[[ Async Public API ]]--
function this:GetVoteDataAsync()
local result = Http.GetGameVotesAsync(placeId)
if not result then
Utility.DebugLog("GameData:GetVoteDataAsync() failed to get web response for placeId "..tostring(placeId))
end
local voteData = {}
local voteTable = result and result["VotingModel"] or nil
if voteTable then
voteData.UpVotes = voteTable["UpVotes"] or 0
voteData.DownVotes = voteTable["DownVotes"] or 0
voteData.UserVote = voteTable["UserVote"]
voteData.CanVote = voteTable["CanVote"] or false
voteData.CantVoteReason = voteTable["ReasonForNotVoteable"] or "PlayGame"
end
return voteData
end
function this:GetGameIconIdAsync()
local iconId = nil
local result = Http.GetGameIconIdAsync(placeId)
if result then
iconId = result["ImageId"]
-- use placeId as backup
if not iconId then
iconId = placeId
end
end
return iconId
end
function this:GetRecommendedGamesAsync()
local result = Http.GetRecommendedGamesAsync(placeId)
if not result then
Utility.DebugLog("GameData:GetRecommendedGamesAsync() failed to get web response for placeId "..tostring(placeId))
return {}
end
local recommendedGames = {}
for i = 1, #result do
local data = result[i]
if data then
local game = {}
-- Temp fix for fixing game names
game.Name = GameData:GetFilteredGameName(data["GameName"], data["Creator"] and data["Creator"]["CreatorName"])
game.PlaceId = data["PlaceId"]
game.IconId = data["ImageId"]
table.insert(recommendedGames, game)
end
end
return recommendedGames
end
function this:GetThumbnailIdsAsync()
local result = Http.GetGameThumbnailsAsync(placeId)
if not result then
Utility.DebugLog("GameData:GetThumbnailIdsAsync() failed to get web response for placeId "..tostring(placeId))
return {}
end
local thumbIds = {}
local thumbIdTable = result["thumbnails"]
if thumbIdTable then
for i = 1, #thumbIdTable do
local data = thumbIdTable[i]
-- AssetTypeId of 1 is a Image (33 is a video if can ever play videos)
if data and data["AssetTypeId"] == 1 then
local assetId = data["AssetId"]
if assetId then
table.insert(thumbIds, assetId)
end
end
end
end
return thumbIds
end
function this:GetBadgeDataAsync()
local result = Http.GetGameBadgeDataAsync(placeId)
if not result then
Utility.DebugLog("GameData:GetBadgeDataAsync() failed to get web response for placeId "..tostring(placeId))
return {}
end
local badgeData = {}
local badgeTable = result["GameBadges"]
if badgeTable then
for i = 1, #badgeTable do
local data = badgeTable[i]
if data then
local badge = {}
badge.Name = data["Name"]
badge.Description = data["Description"]
badge.AssetId = data["BadgeAssetId"]
badge.IsOwned = data["IsOwned"]
badge.Order = i
table.insert(badgeData, badge)
end
end
end
table.sort(badgeData, function(a, b)
if a["IsOwned"] == true and b["IsOwned"] == true then
return a.Order < b.Order
elseif a["IsOwned"] then
return true
elseif b["IsOwned"] then
return false
end
return a.Order < b.Order
end)
return badgeData
end
--[[ Post Public API ]]--
function this:PostFavoriteAsync()
local result = Http.PostFavoriteToggleAsync(placeId)
local success = result and result["success"] == true
EventHub:dispatchEvent(EventHub.Notifications["FavoriteToggle"], success)
if not success then
local reason = "Failed"
-- the floodcheck message is "Whoa. Slow Down.". So if there is a message,
-- let's just say flood check?
if result and result["message"] then
reason = "FloodCheck"
end
return success, reason
else
self.Data["IsFavoritedByUser"] = not self:GetIsFavoritedByUser()
end
return success
end
function this:PostVoteAsync(status)
local result = Http.PostGameVoteAsync(placeId, status)
if not result then
return nil
end
local success = result["Success"] == true
if not success then
return success, result["ModalType"]
end
return success
end
-- Temp fix for fixing game names
if this.Data then
this.Data.Name = GameData:GetFilteredGameName(this.Data.Name, this:GetCreatorName())
end
return this
end
--New GameData Cached
local UserChangedCount = 0
local maxGameCachedDataCount = 5000
local currGameCachedDataCount = 0
local gameCachedData = {}
if ThirdPartyUserService then
ThirdPartyUserService.ActiveUserSignedOut:connect(function()
GameData:FlushGameData()
UserChangedCount = UserChangedCount + 1
end)
end
--Currently, UpdateGameData will be called in three places:
--1. When we request the games in sort, we UpdateGameData with full args(placeId, name, creatorName, iconId, voteData, creatorId)
--2. When we request the Recommended Games in sort, we UpdateGameData with first 4 args(placeId, name, creatorName, iconId)
--3. When we try to GameData:GetGameData(placeId) but found the data has been flushed out, we will UpdateGameData with placeId and re-fetch the data
--args order: placeId, name, creatorName, iconId, voteData, creatorId
function GameData:UpdateGameData(...)
local args = { n = select("#", ...); ... }
if args.n >= 1 then
local placeId = args[1]
local name = args[2]
local creatorName = args[3]
local iconId = args[4]
local voteData = args[5]
local creatorId = args[6]
if not gameCachedData[placeId] then
gameCachedData[placeId] = {}
local this = gameCachedData[placeId]
this.UpdateDebounce = true
this.RelatedGuiObjects = {}
this.AccessCount = 1
local function GetGameDetailsRefreshInterval()
return GlobalSettings.GameDetailsRefreshInterval
end
--Game Details Data
local function RefreshGameDetailsAsync(gameData)
local startCount = UserChangedCount
local Valid = false
local result = Http.GetGameDetailsAsync(gameData.PlaceId)
if not result then
Utility.DebugLog("RefreshGameDetailsAsync() failed to get web response for placeId "..tostring(gameData.PlaceId))
else
if startCount == UserChangedCount then
--for CreatorName and Name, we use the data from initialization unless they were not provided when init
gameData.CreatorName = gameData.CreatorName or result["Builder"] or ""
gameData.Name = gameData.Name or GameData:GetFilteredGameName(result["Name"], gameData.CreatorName)
gameData.Description = result["Description"] or ""
gameData.IsFavorited = result["IsFavoritedByUser"] or false
gameData.LastUpdated = result["Updated"] or ""
gameData.CreationDate = result["Created"] or ""
gameData.MaxPlayers = result["MaxPlayers"] or 0
gameData.OverridesDefaultAvatar = result["OverridesDefaultAvatar"] or false
gameData.IsExperimental = result["IsExperimental"] or false
gameData.CreatorUserId = result["BuilderId"]
gameData.UniverseId = result["UniverseId"] or 0
Valid = true
end
end
return Valid
end
local GameDetailsCachedData = CreateCacheData(this, nil, GetGameDetailsRefreshInterval, RefreshGameDetailsAsync)
--Vote Data
local function RefreshVoteDataAsync(gameData)
local startCount = UserChangedCount
local Valid = false
local result = Http.GetGameVotesAsync(gameData.PlaceId)
if not result then
Utility.DebugLog("RefreshVoteDataAsync() failed to get web response for placeId "..tostring(gameData.PlaceId))
else
if startCount == UserChangedCount then
local voteData = {}
local voteTable = result and result["VotingModel"] or nil
if voteTable then
voteData.UpVotes = voteTable["UpVotes"] or 0
voteData.DownVotes = voteTable["DownVotes"] or 0
voteData.UserVote = voteTable["UserVote"]
voteData.CanVote = voteTable["CanVote"] or false
voteData.CantVoteReason = voteTable["ReasonForNotVoteable"] or "PlayGame"
gameData.VoteData = voteData
Valid = true
end
end
end
return Valid
end
local VoteCachedData = CreateCacheData(this, nil, GetGameDetailsRefreshInterval, RefreshVoteDataAsync)
--Recommended Games
local function RefreshRecommendedGamesAsync(gameData)
local startCount = UserChangedCount
local Valid = false
local result = Http.GetRecommendedGamesAsync(gameData.PlaceId)
if not result then
Utility.DebugLog("RefreshRecommendedGamesAsync() failed to get web response for placeId "..tostring(gameData.PlaceId))
else
if startCount == UserChangedCount then
--clear old data
if gameData.RecommendedGames then
for i = 1, #gameData.RecommendedGames do
local recommendedGamePlaceId = gameData.RecommendedGames[i]
if recommendedGamePlaceId then
local recommendedGameData = GameData:GetGameData(recommendedGamePlaceId)
if recommendedGameData then
recommendedGameData.AccessCount = recommendedGameData.AccessCount - 1
end
end
gameData.RecommendedGames[i]= nil
end
end
local recommendedGames = {}
for i = 1, #result do
local data = result[i]
if data then
-- Temp fix for fixing game names
local creatorName = data["Creator"] and data["Creator"]["CreatorName"]
local name = GameData:GetFilteredGameName(data["GameName"], creatorName)
local placeId = data["PlaceId"]
local iconId = data["ImageId"]
GameData:UpdateGameData(placeId, name, creatorName, iconId)
table.insert(recommendedGames, placeId)
end
end
gameData.RecommendedGames = recommendedGames
Valid = true
end
end
return Valid
end
local RecommendedGamesCachedData = CreateCacheData(this, nil, GetGameDetailsRefreshInterval, RefreshRecommendedGamesAsync)
--ThumbnailIds
local function RefreshThumbnailIdsAsync(gameData)
local startCount = UserChangedCount
local Valid = false
local result = Http.GetGameThumbnailsAsync(gameData.PlaceId)
if not result then
Utility.DebugLog("RefreshThumbnailIdsAsync() failed to get web response for placeId "..tostring(gameData.PlaceId))
else
if startCount == UserChangedCount then
local thumbIds = {}
local thumbIdTable = result["thumbnails"]
if thumbIdTable then
for i = 1, #thumbIdTable do
local data = thumbIdTable[i]
-- AssetTypeId of 1 is a Image (33 is a video if can ever play videos)
if data and data["AssetTypeId"] == 1 then
local assetId = data["AssetId"]
if assetId then
table.insert(thumbIds, assetId)
end
end
end
end
gameData.ThumbnailIds = thumbIds
Valid = true
end
end
return Valid
end
local ThumbnailIdsCachedData = CreateCacheData(this, nil, GetGameDetailsRefreshInterval, RefreshThumbnailIdsAsync)
--Badges
local function RefreshBadgeDataAsync(gameData)
if XboxUpdateBadgeEndpoints then
local startCount = UserChangedCount
local badgesData = {}
local awardedBadges = {}
local nextPageCursor;
repeat
local result = Http.GetBadgesForUniverseAsync(gameData.UniverseId, nextPageCursor)
if result and result.data then
local badgeIds = {}
for _,badgeData in ipairs(result.data) do
if badgeData.enabled then
table.insert(badgesData, badgeData)
table.insert(badgeIds, badgeData.id)
end
end
if #badgeIds > 0 then
local awardedBadgesResult = Http.GetUserAwardedBadgesAsync(
XboxAppState.store:getState().RobloxUser.rbxuid,
badgeIds
)
if awardedBadgesResult and awardedBadgesResult.data then
for _,badge in ipairs(awardedBadgesResult.data) do
awardedBadges[badge.badgeId] = true
end
end
end
nextPageCursor = result.nextPageCursor
else
nextPageCursor = nil
end
until nextPageCursor == nil
if startCount ~= UserChangedCount then
return false
end
local finalBadgesData = {}
for i, badge in ipairs(badgesData) do
local item = {
Name = badge.name,
Description = badge.description,
AssetId = badge.id,
Order = i,
}
if awardedBadges[item.AssetId] then
item.IsOwned = true
end
table.insert(finalBadgesData, item)
end
table.sort(finalBadgesData, function(a, b)
if a["IsOwned"] == true and b["IsOwned"] == true then
return a.Order < b.Order
elseif a["IsOwned"] then
return true
elseif b["IsOwned"] then
return false
end
return a.Order < b.Order
end)
gameData.BadgeData = finalBadgesData
return true
end
local startCount = UserChangedCount
local Valid = false
local result = Http.GetGameBadgeDataAsync(gameData.PlaceId)
if not result then
Utility.DebugLog("GameData:GetBadgeDataAsync() failed to get web response for placeId "..tostring(gameData.PlaceId))
else
if startCount == UserChangedCount then
local badgeData = {}
local badgeTable = result["GameBadges"]
if badgeTable then
for i = 1, #badgeTable do
local data = badgeTable[i]
if data then
local badge = {}
badge.Name = data["Name"]
badge.Description = data["Description"]
badge.AssetId = data["BadgeAssetId"]
badge.IsOwned = data["IsOwned"]
badge.Order = i
table.insert(badgeData, badge)
end
end
end
table.sort(badgeData, function(a, b)
if a["IsOwned"] == true and b["IsOwned"] == true then
return a.Order < b.Order
elseif a["IsOwned"] then
return true
elseif b["IsOwned"] then
return false
end
return a.Order < b.Order
end)
gameData.BadgeData = badgeData
Valid = true
end
end
return Valid
end
local BadgeCachedData = CreateCacheData(this, nil, GetGameDetailsRefreshInterval, RefreshBadgeDataAsync)
--[[ Async Public API ]]--
--We don't want to run so many loading funcs in the BG at intervals,
--so, these reload will be made when the data is requested
function this:GetGameDetailsAsync()
GameDetailsCachedData:Refresh()
local gameData = self or {}
self.OnGetGameDetailsEnd:fire(gameData)
return gameData
end
function this:GetVoteDataAsync()
VoteCachedData:Refresh()
local voteData = self.VoteData or {}
self.OnGetVoteDataEnd:fire(voteData)
return voteData
end
function this:GetRecommendedGamesAsync()
RecommendedGamesCachedData:Refresh()
local recommendedGames = self.RecommendedGames or {}
self.OnGetRecommendedGamesEnd:fire(recommendedGames)
return recommendedGames
end
function this:GetThumbnailIdsAsync()
ThumbnailIdsCachedData:Refresh()
local thumbnailIds = self.ThumbnailIds or {}
self.OnGetThumbnailIdsEnd:fire(thumbnailIds)
return thumbnailIds
end
function this:GetBadgeDataAsync()
BadgeCachedData:Refresh()
local badgeData = self.BadgeData or {}
self.OnGetBadgeDataEnd:fire(badgeData)
return badgeData
end
--We force update IconId whenever it get called
local debounceGetGameIconIdAsync = false
function this:GetGameIconIdAsync()
while debounceGetGameIconIdAsync do
wait()
end
debounceGetGameIconIdAsync = true
local startCount = UserChangedCount
local iconId = nil
local result = Http.GetGameIconIdAsync(placeId)
if result then
iconId = result["ImageId"]
-- use placeId as backup
if not iconId then
iconId = placeId
end
end
if startCount == UserChangedCount then
self.IconId = iconId
end
debounceGetGameIconIdAsync = false
return iconId
end
function this:SetCanVote(value)
local voteData = self.VoteData
voteData.CanVote = value
voteData.CantVoteReason = value and "" or "PlayGame"
end
--[[ Post Public API ]]--
function this:PostFavoriteAsync()
local result = Http.PostFavoriteToggleAsync(placeId)
local success = result and result["success"] == true
local reason = nil
if not success then
reason = "Failed"
-- the floodcheck message is "Whoa. Slow Down.". So if there is a message,
-- let's just say flood check?
if result and result["message"] then
reason = "FloodCheck"
end
else
self.IsFavorited = not self.IsFavorited
end
EventHub:dispatchEvent(EventHub.Notifications["FavoriteToggle"], success, self.PlaceId)
if not success then
return success, reason
else
return success
end
end
function this:PostVoteAsync(newVote)
local result = Http.PostGameVoteAsync(placeId, newVote)
if not result then
return nil
end
local success = result["Success"] == true
if not success then
return success, result["ModalType"]
else
local voteData = self.VoteData
local prevVote = voteData.UserVote
if newVote == true then
voteData.UpVotes = (voteData.UpVotes or 0) + 1
if prevVote == false then
voteData.DownVotes = (voteData.DownVotes or 0) - 1
end
elseif newVote == false then
voteData.DownVotes = (voteData.DownVotes or 0) + 1
if prevVote == true then
voteData.UpVotes = (voteData.UpVotes or 0) - 1
end
elseif newVote == nil then
if prevVote == true then
voteData.UpVotes = (voteData.UpVotes or 0) - 1
elseif prevVote == false then
voteData.DownVotes = (voteData.DownVotes or 0) - 1
end
end
voteData.UserVote = newVote
end
return success
end
--Init Data and Signals
this.OnGetGameDetailsEnd = Utility.Signal()
this.OnGetVoteDataEnd = Utility.Signal()
this.OnGetRecommendedGamesEnd = Utility.Signal()
this.OnGetThumbnailIdsEnd = Utility.Signal()
this.OnGetBadgeDataEnd = Utility.Signal()
if args.n > 1 then
if args.n > 3 then
this.PlaceId = placeId
this.Name = GameData:GetFilteredGameName(name, creatorName)
this.CreatorName = creatorName
this.IconId = iconId
end
--these two are optional
if args.n > 5 then
this.VoteData = voteData
this.CreatorUserId = creatorId
end
else
this.PlaceId = placeId
--No init data, we fetch the essential ones (name, creatorName, iconId)
this:GetGameDetailsAsync()
this:GetGameIconIdAsync()
end
this.UpdateDebounce = false
currGameCachedDataCount = currGameCachedDataCount + 1
--Need to clear Cached Data now
if currGameCachedDataCount > maxGameCachedDataCount then
local gameCachedDataSorted = {}
for key in pairs(gameCachedData) do
--Add key attribute
gameCachedData[key].Key = key
--Recalc the Total AccessCount for every cached data
gameCachedData[key].TotalAccessCount = 0
if gameCachedData[key].RelatedGuiObjects then
local newRelatedGuiObjects = {}
for i = 1, #gameCachedData[key].RelatedGuiObjects do
local relatedGuiObject = gameCachedData[key].RelatedGuiObjects[i]
if relatedGuiObject and relatedGuiObject:IsA("GuiObject") and relatedGuiObject.Parent then
gameCachedData[key].TotalAccessCount = gameCachedData[key].TotalAccessCount + 1
table.insert(newRelatedGuiObjects, relatedGuiObject)
end
end
gameCachedData[key].TotalAccessCount = gameCachedData[key].TotalAccessCount + gameCachedData[key].AccessCount
gameCachedData[key].RelatedGuiObjects = newRelatedGuiObjects
end
table.insert(gameCachedDataSorted, gameCachedData[key])
end
currGameCachedDataCount = #gameCachedDataSorted
--Double check, in case we miscounted the currGameCachedDataCount
if currGameCachedDataCount > maxGameCachedDataCount then
--Put not used data in the back
table.sort(gameCachedDataSorted, function(a, b)
return a.TotalAccessCount > b.TotalAccessCount
end)
--Make sure the removed data is not used anywhere and clear all not in use cached data
--kind of optimization so we don't clear caching for each single overloaded item
while gameCachedDataSorted[#gameCachedDataSorted] and gameCachedDataSorted[#gameCachedDataSorted].TotalAccessCount <= 0 do
local RemovingKey = gameCachedDataSorted[#gameCachedDataSorted].Key
--Clear RecommendedGames Access
if gameCachedData[RemovingKey].RecommendedGames then
local recommendedGames = gameCachedData[RemovingKey].RecommendedGames
for i = 1, #recommendedGames do
local recommendedGamePlaceId = recommendedGames[i]
if recommendedGamePlaceId then
local recommendedGameData = GameData:GetGameData(recommendedGamePlaceId)
if recommendedGameData then
recommendedGameData.AccessCount = recommendedGameData.AccessCount - 1
end
end
recommendedGames[i]= nil
end
end
gameCachedData[RemovingKey] = nil
gameCachedDataSorted[#gameCachedDataSorted] = nil
end
currGameCachedDataCount = #gameCachedDataSorted
end
end
else
local gameData = gameCachedData[placeId]
gameData.UpdateDebounce = true
gameData.AccessCount = gameData.AccessCount and gameData.AccessCount + 1 or 1
--Update Data
if args.n > 3 then
gameData.PlaceId = placeId
gameData.Name = GameData:GetFilteredGameName(name, creatorName)
gameData.CreatorName = creatorName
--We only use the IconId comes with init to avoid game button icon updates
if not gameData.IconId then
gameData.IconId = iconId
end
end
--these two are optional
if args.n > 5 then
gameData.VoteData = voteData
gameData.CreatorUserId = creatorId
end
gameData.UpdateDebounce = false
end
end
end
function GameData:GetGameData(placeId, asyncFetch)
if placeId then
if asyncFetch then
if gameCachedData[placeId] then
--if asyncFetch, we wait until the update is done
while gameCachedData[placeId] and gameCachedData[placeId].UpdateDebounce do
wait()
end
else
--Will refetch data if the data has been flushed from cached data,
--should never happen, as we don't clear cached data as long as there is still any access to it
GameData:UpdateGameData(placeId)
end
end
return gameCachedData[placeId]
end
end
--This is the most robust way to ensure that we don't flush cached gamedata when it's still used on some guiObject.
--Make sure the guiObject already has Parent set up when added
function GameData:AddRelatedGuiObject(placeId, guiObject)
if placeId and guiObject and guiObject:IsA("GuiObject") and guiObject.Parent then
local gameData = GameData:GetGameData(placeId)
if gameData then
table.insert(gameData.RelatedGuiObjects, guiObject)
end
end
end
--This is the most robust way to ensure that we don't flush cached gamedata when it's still used on sort pages.
function GameData:ChangeGameDataAccessCount(placeId, changeValue)
if placeId then
local gameData = GameData:GetGameData(placeId)
if gameData then
gameData.AccessCount = gameData.AccessCount + changeValue
end
end
end
function GameData:FlushGameData()
for placeId,_ in pairs(gameCachedData) do
gameCachedData[placeId] = nil
end
gameCachedData = {}
currGameCachedDataCount = 0
end
return GameData