add gs
This commit is contained in:
@@ -0,0 +1,388 @@
|
||||
-- Written by Kip Turner, Copyright Roblox 2015
|
||||
|
||||
-- Achievement Manager
|
||||
local PlatformService = nil
|
||||
pcall(function() PlatformService = game:GetService('PlatformService') end)
|
||||
local ThirdPartyUserService = nil
|
||||
pcall(function() ThirdPartyUserService = game:GetService('ThirdPartyUserService') end)
|
||||
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local GuiRoot = CoreGui:FindFirstChild("RobloxGui")
|
||||
local Modules = GuiRoot:FindFirstChild("Modules")
|
||||
local ShellModules = Modules:FindFirstChild("Shell")
|
||||
|
||||
local EventHub = require(ShellModules:FindFirstChild('EventHub'))
|
||||
local Http = require(ShellModules:FindFirstChild('Http'))
|
||||
local UserData = require(ShellModules:FindFirstChild('UserData'))
|
||||
local PlatformInterface = require(ShellModules:FindFirstChild('PlatformInterface'))
|
||||
local Alerts = require(ShellModules:FindFirstChild('Alerts'))
|
||||
local ErrorOverlay = require(ShellModules:FindFirstChild('ErrorOverlay'))
|
||||
local ScreenManager = require(ShellModules:FindFirstChild('ScreenManager'))
|
||||
local Utility = require(ShellModules:FindFirstChild('Utility'))
|
||||
|
||||
local SortsData = require(ShellModules:FindFirstChild('SortsData'))
|
||||
local XboxAppState = require(ShellModules:FindFirstChild('AppState'))
|
||||
|
||||
|
||||
--[[ ACHIEVEMENT NAMES --]]
|
||||
-- "Award10DayRoll"
|
||||
-- "Award20DayRoll"
|
||||
-- "Award3DayRoll"
|
||||
-- "AwardDeepDiver"
|
||||
-- "AwardFoursCompany"
|
||||
-- "AwardOneNameManyFaces"
|
||||
-- "AwardPollster"
|
||||
-- "AwardSampler"
|
||||
-- "AwardStrengthInNumbers"
|
||||
-- "AwardWorldTraveler"
|
||||
-- "AwardYouDidIt"
|
||||
-- "GameProgress"
|
||||
-- "MultiplayerRoundEnd"
|
||||
-- "MultiplayerRoundStart"
|
||||
-- "PlayerSessionEnd"
|
||||
-- "PlayerSessionPause"
|
||||
-- "PlayerSessionResume"
|
||||
-- "PlayerSessionStart"
|
||||
-- "Test_XPresses"
|
||||
--[[ END OF ACHIEVEMENT NAMES --]]
|
||||
|
||||
local VIEW_GAMETYPE_ENUM =
|
||||
{
|
||||
AppShell = 0;
|
||||
Game = 1;
|
||||
}
|
||||
|
||||
local GAMES_FOR_YOU_DID_IT = 1
|
||||
local GAMES_FOR_AWARD_SAMPLER = 5
|
||||
|
||||
local DAYS_FOR_3DAYROLL = 3
|
||||
local DAYS_FOR_10DAYROLL = 10
|
||||
local DAYS_FOR_20DAYROLL = 20
|
||||
|
||||
local GAMES_RATED_FOR_POLLSTER = 5
|
||||
|
||||
local PLAY_SECONDS_FOR_DEEP_DIVER = 60 * 60
|
||||
|
||||
local NUMBER_OF_FRIENDS_REQUIRED_FOR_FOURS_COMPANY = 3
|
||||
|
||||
|
||||
local SECONDS_BETWEEN_FOURS_COMPANY_CHECKS = 30
|
||||
|
||||
|
||||
local AchievementManager = {}
|
||||
|
||||
local CurrentView = VIEW_GAMETYPE_ENUM['AppShell']
|
||||
|
||||
local partyUpdateConn = nil
|
||||
|
||||
AchievementManager.AchivementId = {
|
||||
Scout = "2";
|
||||
Explorer = "3";
|
||||
Trailblazer = "4";
|
||||
Pollster = "5";
|
||||
Marathon = "6";
|
||||
OneNameManyFaces = "7";
|
||||
ThreeDayRoll = "8";
|
||||
TenDayRoll = "9";
|
||||
TwentyDayRoll = "10";
|
||||
StrengthInNumbers = "11";
|
||||
FoursCompany = "12";
|
||||
}
|
||||
-- Map ID to trigger name so we can do a look up in SessionAchievementState
|
||||
local AchievementIdToTrigger = {
|
||||
["2"] = "AwardYouDidIt";
|
||||
["3"] = "AwardSampler";
|
||||
["4"] = "AwardWorldTraveler";
|
||||
["5"] = "AwardPollster";
|
||||
["6"] = "AwardDeepDiver";
|
||||
["7"] = "AwardOneNameManyFaces";
|
||||
["8"] = "Award3DayRoll";
|
||||
["9"] = "Award10DayRoll";
|
||||
["10"] = "Award20DayRoll";
|
||||
["11"] = "AwardStrengthInNumbers";
|
||||
["12"] = "AwardFoursCompany";
|
||||
}
|
||||
|
||||
local SessionAchievementState = {}
|
||||
|
||||
local function GetTotalNumberOfGamesOnXbox()
|
||||
-- TODO: is there a programmatic way of figuring this out?
|
||||
return 15
|
||||
end
|
||||
|
||||
local function FilterInGameFriends(onlineFriends, playersInGame)
|
||||
local result = {}
|
||||
|
||||
if onlineFriends and playersInGame then
|
||||
-- Create reverse lookup for speed
|
||||
local playersInGameReverseLookup = {}
|
||||
for _, playerInGame in pairs(playersInGame) do
|
||||
-- TODO: Figure out what the actual lookup
|
||||
if playerInGame['robloxuid'] then
|
||||
playersInGameReverseLookup[playerInGame['robloxuid']] = true
|
||||
end
|
||||
end
|
||||
|
||||
for _, friend in pairs(onlineFriends) do
|
||||
if playersInGameReverseLookup[friend['robloxuid']] then
|
||||
table.insert(result, friend)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
local function OnPlayedGamesChanged()
|
||||
EventHub:dispatchEvent(EventHub.Notifications["PlayedGamesChanged"])
|
||||
spawn(function()
|
||||
local myUserId = XboxAppState.store:getState().RobloxUser.rbxuid
|
||||
if myUserId then
|
||||
local recentCollection
|
||||
-- TODO: is this the right way of getting num of played games?
|
||||
local recentlyPage1
|
||||
recentCollection = SortsData:GetUserRecent()
|
||||
recentlyPage1 = recentCollection and recentCollection:GetSortAsync(0, GetTotalNumberOfGamesOnXbox())
|
||||
local gamesPlayed = recentlyPage1 and #recentlyPage1 or 0
|
||||
|
||||
Utility.DebugLog("You have played:" , gamesPlayed , "games" )
|
||||
if gamesPlayed >= GAMES_FOR_YOU_DID_IT then
|
||||
AchievementManager:SendAchievementEventAsync("AwardYouDidIt")
|
||||
end
|
||||
|
||||
local hasExplorerAchievement = AchievementManager:HasAchievementAsync(AchievementManager.AchivementId.Explorer)
|
||||
if gamesPlayed >= GAMES_FOR_AWARD_SAMPLER then
|
||||
AchievementManager:SendAchievementEventAsync("AwardSampler")
|
||||
|
||||
-- if we didn't have it before then let's unlock UGC
|
||||
if not hasExplorerAchievement then
|
||||
EventHub:dispatchEvent(EventHub.Notifications["UnlockedUGC"], true)
|
||||
else
|
||||
EventHub:dispatchEvent(EventHub.Notifications["UnlockedUGC"], false)
|
||||
end
|
||||
else
|
||||
--if the user has the ExplorerAchievement but hasn't played 5 games
|
||||
--(may happen when user links a new Roblox account to the Xbox account which already has the ExplorerAchievement)
|
||||
if hasExplorerAchievement then
|
||||
EventHub:dispatchEvent(EventHub.Notifications["UnlockedUGC"], false)
|
||||
end
|
||||
end
|
||||
if gamesPlayed >= GetTotalNumberOfGamesOnXbox() then
|
||||
AchievementManager:SendAchievementEventAsync("AwardWorldTraveler")
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function OnJoinedGame()
|
||||
spawn(function()
|
||||
Utility.DebugLog("OnJoinGame: Fours Company check")
|
||||
|
||||
if PlatformService then
|
||||
local lastCheck = 0
|
||||
while CurrentView == VIEW_GAMETYPE_ENUM['Game'] do
|
||||
local now = tick()
|
||||
if now - lastCheck > SECONDS_BETWEEN_FOURS_COMPANY_CHECKS then
|
||||
|
||||
local friendsData = require(ShellModules:FindFirstChild('FriendsData'))
|
||||
local onlineFriends = friendsData.GetOnlineFriendsAsync()
|
||||
|
||||
-- TODO: add actually API
|
||||
local inGamePlayers = PlatformService:GetInGamePlayers()
|
||||
if inGamePlayers and onlineFriends then
|
||||
local inGameFriends = FilterInGameFriends(onlineFriends, inGamePlayers)
|
||||
|
||||
if #inGameFriends >= NUMBER_OF_FRIENDS_REQUIRED_FOR_FOURS_COMPANY then
|
||||
AchievementManager:SendAchievementEventAsync("AwardFoursCompany")
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
lastCheck = now
|
||||
end
|
||||
wait(1)
|
||||
end
|
||||
end
|
||||
end)
|
||||
spawn(function()
|
||||
local startTime = tick()
|
||||
while tick() - startTime < PLAY_SECONDS_FOR_DEEP_DIVER do
|
||||
if CurrentView ~= VIEW_GAMETYPE_ENUM['Game'] then
|
||||
return
|
||||
end
|
||||
wait(1)
|
||||
end
|
||||
if CurrentView == VIEW_GAMETYPE_ENUM['Game'] then
|
||||
AchievementManager:SendAchievementEventAsync("AwardDeepDiver")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function CheckStrengthInNumbers()
|
||||
Utility.DebugLog("PartyTitlePresenceChanged: AwardStrengthInNumbers check")
|
||||
local partyMembers = PlatformInterface:GetPartyMembersAsync()
|
||||
if partyMembers then
|
||||
if PlatformInterface:IsInAParty(partyMembers) then
|
||||
AchievementManager:SendAchievementEventAsync("AwardStrengthInNumbers")
|
||||
if partyUpdateConn then
|
||||
partyUpdateConn:disconnect()
|
||||
partyUpdateConn = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AchievementManager:SendAchievementEventAsync(achievementName)
|
||||
-- Always set session state to awarded, we don't want to block session related achievement progress (UGC for example)
|
||||
-- see: https://forums.xboxlive.com/articles/56661/achievements-and-when-they-arent-unlocking-1.html
|
||||
-- there is an issue with xbox live granting achievements
|
||||
SessionAchievementState[achievementName] = true
|
||||
|
||||
Utility.DebugLog("Achievement Manager - Awarding achievement:" , achievementName)
|
||||
local achievementStatus = nil
|
||||
local success, msg = pcall(function()
|
||||
-- NOTE: Yielding function
|
||||
if not UserSettings().GameSettings:InStudioMode() or game:GetService('UserInputService'):GetPlatform() == Enum.Platform.Windows then
|
||||
achievementStatus = PlatformService:BeginAwardAchievement(achievementName)
|
||||
end
|
||||
end)
|
||||
if not success then
|
||||
-- NOTE: very likely this function ever throws an error but returns error codes
|
||||
Utility.DebugLog("Achievement Manager - Unable to award achievement:" , achievementName , "for reason:" , msg)
|
||||
end
|
||||
|
||||
Utility.DebugLog("Achievement Manager - Achievement:" , achievementName , "event status:" , achievementStatus)
|
||||
end
|
||||
|
||||
EventHub:addEventListener(EventHub.Notifications["UnlockedUGC"], "ShowUnlockedUGCOverlay",
|
||||
function(ShowAlert)
|
||||
if ShowAlert == true then
|
||||
ScreenManager:OpenScreen(ErrorOverlay(Alerts.UnlockedUGC), false)
|
||||
end
|
||||
end)
|
||||
|
||||
EventHub:addEventListener(EventHub.Notifications["AuthenticationSuccess"], "AchievementManager",
|
||||
function()
|
||||
spawn(function()
|
||||
local myUserId = XboxAppState.store:getState().RobloxUser.rbxuid
|
||||
local function stillLoggedIn()
|
||||
local newUserId = XboxAppState.store:getState().RobloxUser.rbxuid
|
||||
return newUserId ~= nil and myUserId == newUserId
|
||||
end
|
||||
|
||||
if myUserId ~= nil then
|
||||
local loggedInResult = Http.GetConsecutiveDaysLoggedInAsync()
|
||||
local daysLoggedIn = loggedInResult and loggedInResult['count']
|
||||
if daysLoggedIn then
|
||||
if daysLoggedIn >= DAYS_FOR_3DAYROLL and stillLoggedIn() then
|
||||
AchievementManager:SendAchievementEventAsync("Award3DayRoll")
|
||||
end
|
||||
if daysLoggedIn >= DAYS_FOR_10DAYROLL and stillLoggedIn() then
|
||||
AchievementManager:SendAchievementEventAsync("Award10DayRoll")
|
||||
end
|
||||
if daysLoggedIn >= DAYS_FOR_20DAYROLL and stillLoggedIn() then
|
||||
AchievementManager:SendAchievementEventAsync("Award20DayRoll")
|
||||
end
|
||||
end
|
||||
--Check if using new "StrengthInNumbers" achievement implementation
|
||||
if PlatformService then
|
||||
local hasStrengthInNumbersAchievement = AchievementManager:HasAchievementAsync(AchievementManager.AchivementId.StrengthInNumbers)
|
||||
if not hasStrengthInNumbersAchievement then
|
||||
--Haven't got "StrengthInNumbers" achievement
|
||||
partyUpdateConn = PlatformService.PartyTitlePresenceChanged:connect(CheckStrengthInNumbers)
|
||||
CheckStrengthInNumbers()
|
||||
end
|
||||
end
|
||||
OnPlayedGamesChanged()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
EventHub:addEventListener(EventHub.Notifications["DonnedDifferentPackage"], "AchievementManager",
|
||||
function(assetId)
|
||||
AchievementManager:SendAchievementEventAsync("AwardOneNameManyFaces")
|
||||
end)
|
||||
|
||||
EventHub:addEventListener(EventHub.Notifications["AvatarEquipSuccess"], "AchievementManager",
|
||||
function(assetId)
|
||||
AchievementManager:SendAchievementEventAsync("AwardOneNameManyFaces")
|
||||
end)
|
||||
|
||||
EventHub:addEventListener(EventHub.Notifications["VotedOnPlace"], "AchievementManager",
|
||||
function()
|
||||
spawn(function()
|
||||
local voteCount = UserData:GetVoteCount()
|
||||
Utility.DebugLog("Vote Check: with vote count" , voteCount)
|
||||
if voteCount >= GAMES_RATED_FOR_POLLSTER then
|
||||
AchievementManager:SendAchievementEventAsync("AwardPollster")
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
if PlatformService then
|
||||
PlatformService.ViewChanged:connect(function(newView)
|
||||
Utility.DebugLog("ViewChanged:" , newView)
|
||||
CurrentView = newView
|
||||
if newView == VIEW_GAMETYPE_ENUM['AppShell'] then
|
||||
Utility.DebugLog("New view is appshell")
|
||||
OnPlayedGamesChanged()
|
||||
elseif newView == VIEW_GAMETYPE_ENUM['Game'] then
|
||||
Utility.DebugLog("New view is game")
|
||||
OnJoinedGame()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local UserChangedCount = 0
|
||||
if ThirdPartyUserService then
|
||||
ThirdPartyUserService.ActiveUserSignedOut:connect(function()
|
||||
UserChangedCount = UserChangedCount + 1
|
||||
SessionAchievementState = {}
|
||||
end)
|
||||
end
|
||||
|
||||
function AchievementManager:HasAchievementAsync(achievementId)
|
||||
local startCount = UserChangedCount
|
||||
if UserSettings().GameSettings:InStudioMode() or game:GetService('UserInputService'):GetPlatform() == Enum.Platform.Windows then
|
||||
SessionAchievementState[AchievementIdToTrigger[achievementId]] = true
|
||||
return true
|
||||
end
|
||||
|
||||
if SessionAchievementState[AchievementIdToTrigger[achievementId]] == true then
|
||||
return true
|
||||
end
|
||||
|
||||
local success, result = pcall(function()
|
||||
return PlatformService:BeginHasAchievement(achievementId)
|
||||
end)
|
||||
if not success then
|
||||
return false
|
||||
end
|
||||
|
||||
--if the result is true, we use it to update SessionAchievementState
|
||||
if startCount == UserChangedCount then
|
||||
if result == true then
|
||||
SessionAchievementState[AchievementIdToTrigger[achievementId]] = result
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
If the result is false or the API fails, we need to use our session state as backup. There is an edge case where locally we
|
||||
grant the achievement, but xbox does not update/grant the achievement for some period of time (like xbox services being down).
|
||||
We want to avoid ever locking the user from UGC if they have in fact unlocked it.
|
||||
Two other cases remain. During the retro check, if xbox services are down, but we have in fact unlocked UGC because we've played
|
||||
5 games, we still unlock. The user will get the notification again however.
|
||||
If the user unlocks UGC then unlinks their account and creates a new Roblox account, and if xbox services are down, since we
|
||||
check games played, UGC will be locked for them. It will remain locked until they play 5 games on the new account, or until
|
||||
xbox services come back up and we can correctly get the state of the achievement. Dan says this is both of these are OK.
|
||||
]]
|
||||
return result or SessionAchievementState[AchievementIdToTrigger[achievementId]]
|
||||
end
|
||||
|
||||
function AchievementManager:AllGamesUnlocked()
|
||||
local achievementId = AchievementManager.AchivementId.Explorer
|
||||
return SessionAchievementState[AchievementIdToTrigger[achievementId]]
|
||||
end
|
||||
|
||||
return AchievementManager
|
||||
Reference in New Issue
Block a user