File size: 4,990 Bytes
b6a38d7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
if FirstLoad then
	s_AchievementReceivedSignals = {}
	s_AchievementUnlockedSignals = {}
	_AchievementsToUnlock = {}
	_UnlockThread = false
	g_SteamIdToAchievementName = {}
	g_AchievementNameToSteamId = {}
end

function OnMsg.DataLoaded()
	g_SteamIdToAchievementName = {}
	g_AchievementNameToSteamId = {}
	ForEachPreset(Achievement, function(achievement, group_list) 
		local steam_id = achievement.steam_id ~= "" and achievement.steam_id or achievement.id
		g_SteamIdToAchievementName[steam_id] = achievement.id
		g_AchievementNameToSteamId[achievement.id] = steam_id
	end)
end

-- Steam account -> AccountStorage sync policy 
TransferUnlockedAchievementsFromSteam = true

function OnSteamAchievementsReceived()
	Msg(s_AchievementReceivedSignals)
end

function OnSteamAchievementUnlocked(unlock_status)
	if unlock_status == "success" then
		Msg(s_AchievementUnlockedSignals)
	end
end

local function WaitGetAchievements()
	if IsSteamLoggedIn() and SteamQueryAchievements(table.values(table.map(AchievementPresets, "steam_id"))) then
		local ok, data
		if WaitMsg( s_AchievementReceivedSignals, 5 * 1000 ) then
			data = SteamGetAchievements()
			if data then
				return true, table.map(data, g_SteamIdToAchievementName)
			end
		end
	end

	return false
end

local function GetSteamAchievementIds(achievements)
	local steam_achievements = { }
	for i, name in ipairs(achievements) do
		if AchievementPresets[name] then
			local steam_id = g_AchievementNameToSteamId[name]
			if not steam_id then
				print("Achievement", name, "doesn't have a Steam ID!")
			else
				table.insert(steam_achievements, steam_id)
			end
		end
	end
	return steam_achievements
end

local function WaitAchievementUnlock(achievements)
	if not Platform.steam or not IsSteamLoggedIn() then
		return true
	end
	local steam_achievements = GetSteamAchievementIds(achievements)
	local steam_unlocked = SteamUnlockAchievements(steam_achievements) and WaitMsg(s_AchievementUnlockedSignals, 5*1000)
	if not steam_unlocked then
		-- Currently our publisher wants to test if achievements work even if they haven't been
		-- created in the steam backend.
		-- To do this we unlock all achievements in AccountStorage even if they haven't been unlocked in steam.
		-- We also pop a notification if steam failed to unlock the achievement.
		Msg("SteamUnlockAchievementsFailed", steam_achievements)
	end
	return true
end

-------------------------------------------[ Higher level functions ]-----------------------------------------------

-- Asynchronous version, launches a thread
function AsyncAchievementUnlock(achievement)
	_AchievementsToUnlock[achievement] = true
	if not IsValidThread(_UnlockThread) then
		_UnlockThread = CreateRealTimeThread( function()
			local achievement = next(_AchievementsToUnlock)
			while achievement do
				if WaitAchievementUnlock{achievement} then
					Msg("AchievementUnlocked", achievement)
				else
					AccountStorage.achievements.unlocked[achievement] = false
				end
				_AchievementsToUnlock[achievement] = nil
				achievement = next(_AchievementsToUnlock)
			end
		end)
	end
end

function SynchronizeAchievements()
	if not IsSteamLoggedIn() then return end
	
	-- check progress, auto-unlock if sufficient progress is made
	for k, v in pairs(AccountStorage.achievements.progress) do
		_CheckAchievementProgress(k, "don't unlock in provider")
	end
	
	local account_storage_unlocked = AccountStorage.achievements.unlocked
	CreateRealTimeThread(function()
		if account_storage_unlocked ~= AccountStorage.achievements.unlocked then
			print("Synchronize achievements aborted!")
			return
		end
		
		-- transfer unlocked achievements to Steam account
		WaitAchievementUnlock(table.keys(account_storage_unlocked))

		if not TransferUnlockedAchievementsFromSteam then
			return
		end
		
		if account_storage_unlocked ~= AccountStorage.achievements.unlocked then
			print("Synchronize achievements aborted!")
			return
		end
		
		-- transfer unlocked achievements to AccountStorage
		local ok, steam_unlocked = WaitGetAchievements()
		
		if account_storage_unlocked ~= AccountStorage.achievements.unlocked then
			print("Synchronize achievements aborted!")
			return
		end
		
		if not ok then
			print("Synchronize achievements failed!")
			return
		end
		
		local save = false
		for i = 1, #steam_unlocked do
			local id = steam_unlocked[i]
			if not account_storage_unlocked[id] then
				save = true
			end
			account_storage_unlocked[id] = true
		end
		if save then
			SaveAccountStorage(5000)
		end
	end)
end

function CheatPlatformUnlockAllAchievements()
	if not Platform.steam or not IsSteamLoggedIn() then end
	local steam_achievements = GetSteamAchievementIds(table.keys(AchievementPresets, true))
	SteamUnlockAchievements(steam_achievements)
end

function CheatPlatformResetAllAchievements()
	if not Platform.steam or not IsSteamLoggedIn() then end
	local steam_achievements = GetSteamAchievementIds(table.keys(AchievementPresets, true))
	SteamResetAchievements(steam_achievements)
end