@quenty/gameproductservice 14.34.7 → 14.34.8-canary.90de6eb.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/package.json +30 -30
- package/src/Client/GameProductServiceClient.lua +1 -0
- package/src/Client/Manager/PlayerProductManagerClient.lua +45 -19
- package/src/Server/Cmdr/GameProductCmdrService.lua +1 -0
- package/src/Server/GameProductService.lua +1 -0
- package/src/Server/Manager/PlayerProductManager.lua +22 -9
- package/src/Shared/Interfaces/PlayerAssetMarketTrackerInterface.lua +1 -0
- package/src/Shared/Interfaces/PlayerProductManagerInterface.lua +1 -0
- package/src/Shared/Ownership/PlayerAssetOwnershipTracker.lua +31 -8
- package/src/Shared/Trackers/PlayerAssetMarketTracker.lua +70 -19
- package/src/Shared/Trackers/PlayerProductManagerBase.lua +62 -24
- package/test/scripts/Client/ClientMain.client.lua +1 -0
- package/test/scripts/Server/ServerMain.server.lua +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [14.34.8-canary.90de6eb.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/gameproductservice@14.34.7...@quenty/gameproductservice@14.34.8-canary.90de6eb.0) (2026-01-03)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @quenty/gameproductservice
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
## [14.34.7](https://github.com/Quenty/NevermoreEngine/compare/@quenty/gameproductservice@14.34.6...@quenty/gameproductservice@14.34.7) (2025-12-31)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @quenty/gameproductservice
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/gameproductservice",
|
|
3
|
-
"version": "14.34.
|
|
3
|
+
"version": "14.34.8-canary.90de6eb.0",
|
|
4
4
|
"description": "Generalized monetization system for handling products and purchases correctly.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -27,34 +27,34 @@
|
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@quenty/attributeutils": "
|
|
31
|
-
"@quenty/avatareditorutils": "
|
|
32
|
-
"@quenty/baseobject": "
|
|
33
|
-
"@quenty/binder": "
|
|
34
|
-
"@quenty/brio": "
|
|
35
|
-
"@quenty/cmdrservice": "
|
|
36
|
-
"@quenty/enumutils": "
|
|
37
|
-
"@quenty/gameconfig": "
|
|
38
|
-
"@quenty/instanceutils": "
|
|
39
|
-
"@quenty/loader": "
|
|
40
|
-
"@quenty/maid": "
|
|
41
|
-
"@quenty/marketplaceutils": "
|
|
42
|
-
"@quenty/observablecollection": "
|
|
43
|
-
"@quenty/playerbinder": "
|
|
44
|
-
"@quenty/playerutils": "
|
|
45
|
-
"@quenty/promise": "
|
|
46
|
-
"@quenty/promisemaid": "
|
|
47
|
-
"@quenty/receiptprocessing": "
|
|
48
|
-
"@quenty/remoting": "
|
|
49
|
-
"@quenty/rx": "
|
|
50
|
-
"@quenty/rxbinderutils": "
|
|
51
|
-
"@quenty/servicebag": "
|
|
52
|
-
"@quenty/signal": "
|
|
53
|
-
"@quenty/statestack": "
|
|
54
|
-
"@quenty/string": "
|
|
55
|
-
"@quenty/table": "
|
|
56
|
-
"@quenty/tie": "
|
|
57
|
-
"@quenty/valueobject": "
|
|
30
|
+
"@quenty/attributeutils": "14.20.6-canary.90de6eb.0",
|
|
31
|
+
"@quenty/avatareditorutils": "7.25.7-canary.90de6eb.0",
|
|
32
|
+
"@quenty/baseobject": "10.9.1-canary.90de6eb.0",
|
|
33
|
+
"@quenty/binder": "14.25.7-canary.90de6eb.0",
|
|
34
|
+
"@quenty/brio": "14.20.5-canary.90de6eb.0",
|
|
35
|
+
"@quenty/cmdrservice": "13.29.8-canary.90de6eb.0",
|
|
36
|
+
"@quenty/enumutils": "3.4.3-canary.90de6eb.0",
|
|
37
|
+
"@quenty/gameconfig": "12.33.8-canary.90de6eb.0",
|
|
38
|
+
"@quenty/instanceutils": "13.20.6-canary.90de6eb.0",
|
|
39
|
+
"@quenty/loader": "10.9.1-canary.90de6eb.0",
|
|
40
|
+
"@quenty/maid": "3.5.1-canary.90de6eb.0",
|
|
41
|
+
"@quenty/marketplaceutils": "11.13.4-canary.90de6eb.0",
|
|
42
|
+
"@quenty/observablecollection": "12.24.7-canary.90de6eb.0",
|
|
43
|
+
"@quenty/playerbinder": "14.25.7-canary.90de6eb.0",
|
|
44
|
+
"@quenty/playerutils": "8.21.7-canary.90de6eb.0",
|
|
45
|
+
"@quenty/promise": "10.12.4-canary.90de6eb.0",
|
|
46
|
+
"@quenty/promisemaid": "5.12.4-canary.90de6eb.0",
|
|
47
|
+
"@quenty/receiptprocessing": "7.23.7-canary.90de6eb.0",
|
|
48
|
+
"@quenty/remoting": "12.21.6-canary.90de6eb.0",
|
|
49
|
+
"@quenty/rx": "13.20.4-canary.90de6eb.0",
|
|
50
|
+
"@quenty/rxbinderutils": "14.25.7-canary.90de6eb.0",
|
|
51
|
+
"@quenty/servicebag": "11.13.4-canary.90de6eb.0",
|
|
52
|
+
"@quenty/signal": "7.11.3-canary.90de6eb.0",
|
|
53
|
+
"@quenty/statestack": "14.22.7-canary.90de6eb.0",
|
|
54
|
+
"@quenty/string": "3.3.4-canary.90de6eb.0",
|
|
55
|
+
"@quenty/table": "3.8.0",
|
|
56
|
+
"@quenty/tie": "10.26.7-canary.90de6eb.0",
|
|
57
|
+
"@quenty/valueobject": "13.21.7-canary.90de6eb.0"
|
|
58
58
|
},
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "90de6ebb6e0cb5e6798e08b312cb1864c1d3354c"
|
|
60
60
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
@client
|
|
3
4
|
@class PlayerProductManagerClient
|
|
@@ -18,16 +19,33 @@ local PlayerProductManagerBase = require("PlayerProductManagerBase")
|
|
|
18
19
|
local PlayerProductManagerInterface = require("PlayerProductManagerInterface")
|
|
19
20
|
local Promise = require("Promise")
|
|
20
21
|
local Remoting = require("Remoting")
|
|
22
|
+
local ServiceBag = require("ServiceBag")
|
|
21
23
|
|
|
22
24
|
local PlayerProductManagerClient = setmetatable({}, PlayerProductManagerBase)
|
|
23
25
|
PlayerProductManagerClient.ClassName = "PlayerProductManagerClient"
|
|
24
26
|
PlayerProductManagerClient.__index = PlayerProductManagerClient
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
export type PlayerProductManagerClient =
|
|
29
|
+
typeof(setmetatable(
|
|
30
|
+
{} :: {
|
|
31
|
+
_obj: Player,
|
|
32
|
+
_player: Player,
|
|
33
|
+
_serviceBag: ServiceBag.ServiceBag,
|
|
34
|
+
_remoting: Remoting.Remoting,
|
|
28
35
|
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
_avatarEditorInventoryServiceClient: AvatarEditorInventoryServiceClient.AvatarEditorInventoryServiceClient,
|
|
37
|
+
_catalogSearchServiceCache: CatalogSearchServiceCache.CatalogSearchServiceCache,
|
|
38
|
+
},
|
|
39
|
+
{} :: typeof({ __index = PlayerProductManagerClient })
|
|
40
|
+
))
|
|
41
|
+
& PlayerProductManagerBase.PlayerProductManagerBase
|
|
42
|
+
|
|
43
|
+
function PlayerProductManagerClient.new(player: Player, serviceBag: ServiceBag.ServiceBag): PlayerProductManagerClient
|
|
44
|
+
local self: PlayerProductManagerClient =
|
|
45
|
+
setmetatable(PlayerProductManagerBase.new(player, serviceBag) :: any, PlayerProductManagerClient)
|
|
46
|
+
|
|
47
|
+
self._avatarEditorInventoryServiceClient = self._serviceBag:GetService(AvatarEditorInventoryServiceClient :: any)
|
|
48
|
+
self._catalogSearchServiceCache = self._serviceBag:GetService(CatalogSearchServiceCache :: any)
|
|
31
49
|
|
|
32
50
|
if self._obj == Players.LocalPlayer then
|
|
33
51
|
self._remoting = self._maid:Add(Remoting.new(self._obj, "PlayerProductManager", Remoting.Realms.CLIENT))
|
|
@@ -52,11 +70,11 @@ end
|
|
|
52
70
|
Gets the current player
|
|
53
71
|
@return Player
|
|
54
72
|
]=]
|
|
55
|
-
function PlayerProductManagerClient
|
|
73
|
+
function PlayerProductManagerClient.GetPlayer(self: PlayerProductManagerClient): Player
|
|
56
74
|
return self._obj
|
|
57
75
|
end
|
|
58
76
|
|
|
59
|
-
function PlayerProductManagerClient
|
|
77
|
+
function PlayerProductManagerClient._setupAssetTracker(self: PlayerProductManagerClient): ()
|
|
60
78
|
local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.ASSET)
|
|
61
79
|
local assetOwnership = assert(tracker:GetOwnershipTracker(), "Missing ownershipTracker on client")
|
|
62
80
|
|
|
@@ -73,14 +91,18 @@ function PlayerProductManagerClient:_setupAssetTracker()
|
|
|
73
91
|
end))
|
|
74
92
|
end
|
|
75
93
|
|
|
76
|
-
function PlayerProductManagerClient
|
|
94
|
+
function PlayerProductManagerClient._setupMembershipTracker(self: PlayerProductManagerClient): ()
|
|
77
95
|
local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.MEMBERSHIP)
|
|
78
96
|
|
|
79
97
|
self._maid:GiveTask(MarketplaceService.PromptPremiumPurchaseFinished:Connect(function()
|
|
80
|
-
|
|
98
|
+
-- TODO: Fix typing, these expect a number
|
|
99
|
+
tracker:HandlePromptClosedEvent(Enum.MembershipType.Premium :: any)
|
|
81
100
|
|
|
82
101
|
-- Not great behavior but whatever
|
|
83
|
-
tracker:HandlePurchaseEvent(
|
|
102
|
+
tracker:HandlePurchaseEvent(
|
|
103
|
+
Enum.MembershipType.Premium :: any,
|
|
104
|
+
self._obj.MembershipType == Enum.MembershipType.Premium
|
|
105
|
+
)
|
|
84
106
|
end))
|
|
85
107
|
|
|
86
108
|
-- I think this only fires on the server...
|
|
@@ -93,7 +115,7 @@ function PlayerProductManagerClient:_setupMembershipTracker()
|
|
|
93
115
|
end))
|
|
94
116
|
end
|
|
95
117
|
|
|
96
|
-
function PlayerProductManagerClient
|
|
118
|
+
function PlayerProductManagerClient._setupSubscriptionTracker(self: PlayerProductManagerClient): ()
|
|
97
119
|
local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.SUBSCRIPTION)
|
|
98
120
|
|
|
99
121
|
-- Main event
|
|
@@ -126,7 +148,7 @@ function PlayerProductManagerClient:_setupSubscriptionTracker()
|
|
|
126
148
|
end))
|
|
127
149
|
end
|
|
128
150
|
|
|
129
|
-
function PlayerProductManagerClient
|
|
151
|
+
function PlayerProductManagerClient._connectBulkPurchaseMarketplace(self: PlayerProductManagerClient): ()
|
|
130
152
|
self._maid:GiveTask(MarketplaceService.PromptBulkPurchaseFinished:Connect(function(player, status, results)
|
|
131
153
|
if player ~= self._obj then
|
|
132
154
|
return
|
|
@@ -160,7 +182,7 @@ function PlayerProductManagerClient:_connectBulkPurchaseMarketplace()
|
|
|
160
182
|
end))
|
|
161
183
|
end
|
|
162
184
|
|
|
163
|
-
function PlayerProductManagerClient
|
|
185
|
+
function PlayerProductManagerClient._setupProductTracker(self: PlayerProductManagerClient): ()
|
|
164
186
|
local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.PRODUCT)
|
|
165
187
|
|
|
166
188
|
self._maid:GiveTask(
|
|
@@ -184,7 +206,7 @@ function PlayerProductManagerClient:_setupProductTracker()
|
|
|
184
206
|
end))
|
|
185
207
|
end
|
|
186
208
|
|
|
187
|
-
function PlayerProductManagerClient
|
|
209
|
+
function PlayerProductManagerClient._connectGamePassTracker(self: PlayerProductManagerClient): ()
|
|
188
210
|
local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.PASS)
|
|
189
211
|
|
|
190
212
|
self._maid:GiveTask(
|
|
@@ -201,13 +223,13 @@ function PlayerProductManagerClient:_connectGamePassTracker()
|
|
|
201
223
|
)
|
|
202
224
|
end
|
|
203
225
|
|
|
204
|
-
function PlayerProductManagerClient
|
|
226
|
+
function PlayerProductManagerClient._setupBundleTracker(self: PlayerProductManagerClient): ()
|
|
205
227
|
local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.BUNDLE)
|
|
206
228
|
|
|
207
229
|
local bundleOwnership = assert(tracker:GetOwnershipTracker(), "Missing ownershipTracker on client")
|
|
208
230
|
|
|
209
231
|
bundleOwnership:SetQueryOwnershipCallback(function(assetId)
|
|
210
|
-
return self:_promiseBulkOwnsBundleQuery(assetId
|
|
232
|
+
return self:_promiseBulkOwnsBundleQuery(assetId)
|
|
211
233
|
end)
|
|
212
234
|
|
|
213
235
|
self._maid:GiveTask(MarketplaceService.PromptBundlePurchaseFinished:Connect(function(player, bundleId, isPurchased)
|
|
@@ -220,7 +242,7 @@ function PlayerProductManagerClient:_setupBundleTracker()
|
|
|
220
242
|
end))
|
|
221
243
|
end
|
|
222
244
|
|
|
223
|
-
function PlayerProductManagerClient
|
|
245
|
+
function PlayerProductManagerClient._promiseBulkOwnsAssetQuery(self: PlayerProductManagerClient, assetId)
|
|
224
246
|
if self._avatarEditorInventoryServiceClient:IsInventoryAccessAllowed() then
|
|
225
247
|
-- When scrolling through a ton of entries in the avatar editor we want to query
|
|
226
248
|
-- this is typically faster. We really hope we aren't the Roblox account.
|
|
@@ -229,7 +251,8 @@ function PlayerProductManagerClient:_promiseBulkOwnsAssetQuery(assetId)
|
|
|
229
251
|
:Then(function(itemDetails)
|
|
230
252
|
-- https://devforum.roblox.com/t/avatareditorservicegetitemdetails-returns-ownership-where-as-avatareditorservicegetbatchitemdetails-does-not/3257431
|
|
231
253
|
|
|
232
|
-
local assetType
|
|
254
|
+
local assetType: Enum.AvatarAssetType? =
|
|
255
|
+
EnumUtils.toEnum(Enum.AvatarAssetType, itemDetails.AssetType) :: any
|
|
233
256
|
if not assetType then
|
|
234
257
|
-- TODO: Fallback to standard query?
|
|
235
258
|
return Promise.rejected("Failed to get assetType")
|
|
@@ -246,8 +269,11 @@ function PlayerProductManagerClient:_promiseBulkOwnsAssetQuery(assetId)
|
|
|
246
269
|
return MarketplaceUtils.promisePlayerOwnsAsset(self._player, assetId)
|
|
247
270
|
end
|
|
248
271
|
|
|
249
|
-
function PlayerProductManagerClient
|
|
272
|
+
function PlayerProductManagerClient._promiseBulkOwnsBundleQuery(self: PlayerProductManagerClient, bundleId: number)
|
|
250
273
|
return MarketplaceUtils.promisePlayerOwnsBundle(self._player, bundleId)
|
|
251
274
|
end
|
|
252
275
|
|
|
253
|
-
return Binder.new(
|
|
276
|
+
return Binder.new(
|
|
277
|
+
"PlayerProductManager",
|
|
278
|
+
PlayerProductManagerClient :: any
|
|
279
|
+
) :: Binder.Binder<PlayerProductManagerClient>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!nonstrict
|
|
1
2
|
--[=[
|
|
2
3
|
Handles product prompting state on the server
|
|
3
4
|
|
|
@@ -17,11 +18,22 @@ local PlayerProductManagerBase = require("PlayerProductManagerBase")
|
|
|
17
18
|
local PlayerProductManagerInterface = require("PlayerProductManagerInterface")
|
|
18
19
|
local ReceiptProcessingService = require("ReceiptProcessingService")
|
|
19
20
|
local Remoting = require("Remoting")
|
|
21
|
+
local ServiceBag = require("ServiceBag")
|
|
20
22
|
|
|
21
23
|
local PlayerProductManager = setmetatable({}, PlayerProductManagerBase)
|
|
22
24
|
PlayerProductManager.ClassName = "PlayerProductManager"
|
|
23
25
|
PlayerProductManager.__index = PlayerProductManager
|
|
24
26
|
|
|
27
|
+
export type PlayerProductManager =
|
|
28
|
+
typeof(setmetatable(
|
|
29
|
+
{} :: {
|
|
30
|
+
_serviceBag: ServiceBag.ServiceBag,
|
|
31
|
+
_receiptProcessingService: ReceiptProcessingService.ReceiptProcessingService,
|
|
32
|
+
},
|
|
33
|
+
{} :: typeof({ __index = PlayerProductManager })
|
|
34
|
+
))
|
|
35
|
+
& PlayerProductManagerBase.PlayerProductManagerBase
|
|
36
|
+
|
|
25
37
|
--[=[
|
|
26
38
|
Managers players products and purchase state. Should be retrieved via binder.
|
|
27
39
|
|
|
@@ -29,8 +41,9 @@ PlayerProductManager.__index = PlayerProductManager
|
|
|
29
41
|
@param serviceBag ServiceBag
|
|
30
42
|
@return PlayerProductManager
|
|
31
43
|
]=]
|
|
32
|
-
function PlayerProductManager.new(player, serviceBag)
|
|
33
|
-
local self =
|
|
44
|
+
function PlayerProductManager.new(player: Player, serviceBag: ServiceBag.ServiceBag): PlayerProductManager
|
|
45
|
+
local self: PlayerProductManager =
|
|
46
|
+
setmetatable(PlayerProductManagerBase.new(player, serviceBag) :: any, PlayerProductManager)
|
|
34
47
|
|
|
35
48
|
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
36
49
|
self._receiptProcessingService = self._serviceBag:GetService(ReceiptProcessingService)
|
|
@@ -54,11 +67,11 @@ function PlayerProductManager.new(player, serviceBag)
|
|
|
54
67
|
return self
|
|
55
68
|
end
|
|
56
69
|
|
|
57
|
-
function PlayerProductManager
|
|
70
|
+
function PlayerProductManager._setupRemoting(self: PlayerProductManager): ()
|
|
58
71
|
self._remoting = self._maid:Add(Remoting.Server.new(self._obj, "PlayerProductManager", Remoting.Realms.SERVER))
|
|
59
72
|
end
|
|
60
73
|
|
|
61
|
-
function PlayerProductManager
|
|
74
|
+
function PlayerProductManager._setupAssetTracker(self: PlayerProductManager): ()
|
|
62
75
|
local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.ASSET)
|
|
63
76
|
|
|
64
77
|
self._maid:GiveTask(self._remoting.AssetPromptPurchaseFinished:Connect(function(player, assetId, isPurchased)
|
|
@@ -72,7 +85,7 @@ function PlayerProductManager:_setupAssetTracker()
|
|
|
72
85
|
end))
|
|
73
86
|
end
|
|
74
87
|
|
|
75
|
-
function PlayerProductManager
|
|
88
|
+
function PlayerProductManager._setupProductTracker(self: PlayerProductManager): ()
|
|
76
89
|
local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.PRODUCT)
|
|
77
90
|
|
|
78
91
|
-- Source of truth for purchase is here
|
|
@@ -104,7 +117,7 @@ function PlayerProductManager:_setupProductTracker()
|
|
|
104
117
|
)
|
|
105
118
|
end
|
|
106
119
|
|
|
107
|
-
function PlayerProductManager
|
|
120
|
+
function PlayerProductManager._setupPassTracker(self: PlayerProductManager): ()
|
|
108
121
|
local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.PASS)
|
|
109
122
|
|
|
110
123
|
self._maid:GiveTask(self._remoting.PromptGamePassPurchaseFinished:Connect(function(player, gamePassId, isPurchased)
|
|
@@ -118,7 +131,7 @@ function PlayerProductManager:_setupPassTracker()
|
|
|
118
131
|
end))
|
|
119
132
|
end
|
|
120
133
|
|
|
121
|
-
function PlayerProductManager
|
|
134
|
+
function PlayerProductManager._setupMembershipTracker(self: PlayerProductManager): ()
|
|
122
135
|
local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.MEMBERSHIP)
|
|
123
136
|
|
|
124
137
|
self._maid:GiveTask(Players.PlayerMembershipChanged:Connect(function(player)
|
|
@@ -130,7 +143,7 @@ function PlayerProductManager:_setupMembershipTracker()
|
|
|
130
143
|
end))
|
|
131
144
|
end
|
|
132
145
|
|
|
133
|
-
function PlayerProductManager
|
|
146
|
+
function PlayerProductManager._setupSubscriptionTracker(self: PlayerProductManager): ()
|
|
134
147
|
self._remoting.UserSubscriptionStatusChanged:DeclareEvent()
|
|
135
148
|
|
|
136
149
|
local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.SUBSCRIPTION)
|
|
@@ -163,7 +176,7 @@ function PlayerProductManager:_setupSubscriptionTracker()
|
|
|
163
176
|
end))
|
|
164
177
|
end
|
|
165
178
|
|
|
166
|
-
function PlayerProductManager
|
|
179
|
+
function PlayerProductManager._setupBundleTracker(self: PlayerProductManager): ()
|
|
167
180
|
local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.BUNDLE)
|
|
168
181
|
|
|
169
182
|
self._maid:GiveTask(MarketplaceService.PromptBundlePurchaseFinished:Connect(function(player, bundleId, isPurchased)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
This tracking is relatively complicated because we want to track both
|
|
3
4
|
ownership from attributes (can be customized locally), as well as async
|
|
@@ -10,6 +11,8 @@ local require = require(script.Parent.loader).load(script)
|
|
|
10
11
|
|
|
11
12
|
local BaseObject = require("BaseObject")
|
|
12
13
|
local GameConfigAssetTypeUtils = require("GameConfigAssetTypeUtils")
|
|
14
|
+
local GameConfigAssetTypes = require("GameConfigAssetTypes")
|
|
15
|
+
local GameConfigPicker = require("GameConfigPicker")
|
|
13
16
|
local Maid = require("Maid")
|
|
14
17
|
local Observable = require("Observable")
|
|
15
18
|
local ObservableSet = require("ObservableSet")
|
|
@@ -20,10 +23,30 @@ local PlayerAssetOwnershipTracker = setmetatable({}, BaseObject)
|
|
|
20
23
|
PlayerAssetOwnershipTracker.ClassName = "PlayerAssetOwnershipTracker"
|
|
21
24
|
PlayerAssetOwnershipTracker.__index = PlayerAssetOwnershipTracker
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
export type PlayerAssetOwnershipTracker =
|
|
27
|
+
typeof(setmetatable(
|
|
28
|
+
{} :: {
|
|
29
|
+
_player: Player,
|
|
30
|
+
_configPicker: any,
|
|
31
|
+
_assetType: GameConfigAssetTypes.GameConfigAssetType,
|
|
32
|
+
_marketTracker: any,
|
|
33
|
+
_ownershipCallback: ValueObject.ValueObject<(number) -> Promise.Promise<boolean> | nil>,
|
|
34
|
+
_ownedAssetIdSet: ObservableSet.ObservableSet<number>,
|
|
35
|
+
_assetOwnershipPromiseCache: { [number]: Promise.Promise<boolean> | boolean },
|
|
36
|
+
},
|
|
37
|
+
{} :: typeof({ __index = PlayerAssetOwnershipTracker })
|
|
38
|
+
))
|
|
39
|
+
& BaseObject.BaseObject
|
|
40
|
+
|
|
41
|
+
function PlayerAssetOwnershipTracker.new(
|
|
42
|
+
player: Player,
|
|
43
|
+
configPicker: GameConfigPicker.GameConfigPicker,
|
|
44
|
+
assetType: GameConfigAssetTypes.GameConfigAssetType,
|
|
45
|
+
marketTracker: any
|
|
46
|
+
): PlayerAssetOwnershipTracker
|
|
24
47
|
assert(GameConfigAssetTypeUtils.isAssetType(assetType), "Bad assetType")
|
|
25
48
|
|
|
26
|
-
local self = setmetatable(BaseObject.new(), PlayerAssetOwnershipTracker)
|
|
49
|
+
local self: PlayerAssetOwnershipTracker = setmetatable(BaseObject.new() :: any, PlayerAssetOwnershipTracker)
|
|
27
50
|
|
|
28
51
|
self._player = assert(player, "No player")
|
|
29
52
|
self._configPicker = assert(configPicker, "No configPicker")
|
|
@@ -46,7 +69,7 @@ end
|
|
|
46
69
|
Sets the callback which will query ownership
|
|
47
70
|
@param promiseOwnsAsset function
|
|
48
71
|
]=]
|
|
49
|
-
function PlayerAssetOwnershipTracker:SetQueryOwnershipCallback(promiseOwnsAsset)
|
|
72
|
+
function PlayerAssetOwnershipTracker:SetQueryOwnershipCallback(promiseOwnsAsset: (any) -> Promise.Promise<boolean>?): ()
|
|
50
73
|
assert(type(promiseOwnsAsset) == "function" or promiseOwnsAsset == nil, "Bad promiseOwnsAsset")
|
|
51
74
|
|
|
52
75
|
if self._ownershipCallback.Value == promiseOwnsAsset then
|
|
@@ -57,7 +80,7 @@ function PlayerAssetOwnershipTracker:SetQueryOwnershipCallback(promiseOwnsAsset)
|
|
|
57
80
|
self._ownershipCallback.Value = promiseOwnsAsset
|
|
58
81
|
end
|
|
59
82
|
|
|
60
|
-
function PlayerAssetOwnershipTracker:_promiseQueryAssetId(assetId: number)
|
|
83
|
+
function PlayerAssetOwnershipTracker:_promiseQueryAssetId(assetId: number): Promise.Promise<boolean>?
|
|
61
84
|
assert(type(assetId) == "number", "Bad assetId")
|
|
62
85
|
|
|
63
86
|
local promiseOwnershipCallback = self._ownershipCallback.Value
|
|
@@ -103,7 +126,7 @@ end
|
|
|
103
126
|
@param idOrKey number
|
|
104
127
|
@param ownsAsset boolean
|
|
105
128
|
]=]
|
|
106
|
-
function PlayerAssetOwnershipTracker:SetOwnership(idOrKey, ownsAsset)
|
|
129
|
+
function PlayerAssetOwnershipTracker:SetOwnership(idOrKey, ownsAsset: boolean): ()
|
|
107
130
|
assert(type(idOrKey) == "number" or type(idOrKey) == "string", "idOrKey")
|
|
108
131
|
assert(type(ownsAsset) == "boolean", "Bad ownsAsset")
|
|
109
132
|
|
|
@@ -155,7 +178,7 @@ end
|
|
|
155
178
|
@param idOrKey number | number
|
|
156
179
|
@return Observable<boolean>
|
|
157
180
|
]=]
|
|
158
|
-
function PlayerAssetOwnershipTracker:ObserveOwnsAsset(idOrKey)
|
|
181
|
+
function PlayerAssetOwnershipTracker:ObserveOwnsAsset(idOrKey): Observable.Observable<boolean>
|
|
159
182
|
assert(type(idOrKey) == "number" or type(idOrKey) == "string", "Bad idOrKey")
|
|
160
183
|
|
|
161
184
|
-- TODO: Get rid of several concepts here, including well known assets, attributes, and more
|
|
@@ -179,7 +202,7 @@ function PlayerAssetOwnershipTracker:ObserveOwnsAsset(idOrKey)
|
|
|
179
202
|
end))
|
|
180
203
|
|
|
181
204
|
return topMaid
|
|
182
|
-
end)
|
|
205
|
+
end) :: any
|
|
183
206
|
elseif type(idOrKey) == "number" then
|
|
184
207
|
return Observable.new(function(sub)
|
|
185
208
|
local maid = Maid.new()
|
|
@@ -193,7 +216,7 @@ function PlayerAssetOwnershipTracker:ObserveOwnsAsset(idOrKey)
|
|
|
193
216
|
end)
|
|
194
217
|
|
|
195
218
|
return maid
|
|
196
|
-
end)
|
|
219
|
+
end) :: any
|
|
197
220
|
else
|
|
198
221
|
error("Bad idOrKey")
|
|
199
222
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Tracks a single asset type for pending purchase prompts.
|
|
3
4
|
|
|
@@ -7,10 +8,12 @@
|
|
|
7
8
|
local require = require(script.Parent.loader).load(script)
|
|
8
9
|
|
|
9
10
|
local BaseObject = require("BaseObject")
|
|
11
|
+
local Brio = require("Brio")
|
|
10
12
|
local GameConfigAssetTypeUtils = require("GameConfigAssetTypeUtils")
|
|
11
13
|
local GameConfigAssetTypes = require("GameConfigAssetTypes")
|
|
12
14
|
local Maid = require("Maid")
|
|
13
15
|
local Observable = require("Observable")
|
|
16
|
+
local PlayerAssetOwnershipTracker = require("PlayerAssetOwnershipTracker")
|
|
14
17
|
local Promise = require("Promise")
|
|
15
18
|
local Signal = require("Signal")
|
|
16
19
|
local ValueObject = require("ValueObject")
|
|
@@ -19,6 +22,28 @@ local PlayerAssetMarketTracker = setmetatable({}, BaseObject)
|
|
|
19
22
|
PlayerAssetMarketTracker.ClassName = "PlayerAssetMarketTracker"
|
|
20
23
|
PlayerAssetMarketTracker.__index = PlayerAssetMarketTracker
|
|
21
24
|
|
|
25
|
+
export type PlayerAssetMarketTracker =
|
|
26
|
+
typeof(setmetatable(
|
|
27
|
+
{} :: {
|
|
28
|
+
_assetType: GameConfigAssetTypes.GameConfigAssetType,
|
|
29
|
+
_convertIds: (string | number) -> number?,
|
|
30
|
+
_observeIdsBrio: (string | number) -> Observable.Observable<Brio.Brio<number>>,
|
|
31
|
+
_pendingPurchasePromises: { Promise.Promise<boolean> },
|
|
32
|
+
_pendingPromptOpenPromises: { Promise.Promise<boolean> },
|
|
33
|
+
_purchasedThisSession: { [number]: boolean },
|
|
34
|
+
_promptsOpenCount: ValueObject.ValueObject<number>,
|
|
35
|
+
_ownershipTracker: PlayerAssetOwnershipTracker.PlayerAssetOwnershipTracker?,
|
|
36
|
+
|
|
37
|
+
Purchased: Signal.Signal<number>,
|
|
38
|
+
PromptClosed: Signal.Signal<(number, boolean)>,
|
|
39
|
+
ShowPromptRequested: Signal.Signal<number>,
|
|
40
|
+
|
|
41
|
+
_promiseNoPromptOpen: Promise.Promise<()>?,
|
|
42
|
+
},
|
|
43
|
+
{} :: typeof({ __index = PlayerAssetMarketTracker })
|
|
44
|
+
))
|
|
45
|
+
& BaseObject.BaseObject
|
|
46
|
+
|
|
22
47
|
--[=[
|
|
23
48
|
Constructs a new market tracker. Generally you should not need to use
|
|
24
49
|
this directly.
|
|
@@ -28,10 +53,14 @@ PlayerAssetMarketTracker.__index = PlayerAssetMarketTracker
|
|
|
28
53
|
@param observeIdsBrio function
|
|
29
54
|
@return PlayerAssetMarketTracker
|
|
30
55
|
]=]
|
|
31
|
-
function PlayerAssetMarketTracker.new(
|
|
56
|
+
function PlayerAssetMarketTracker.new(
|
|
57
|
+
assetType: GameConfigAssetTypes.GameConfigAssetType,
|
|
58
|
+
convertIds,
|
|
59
|
+
observeIdsBrio
|
|
60
|
+
): PlayerAssetMarketTracker
|
|
32
61
|
assert(GameConfigAssetTypeUtils.isAssetType(assetType), "Bad assetType")
|
|
33
62
|
|
|
34
|
-
local self = setmetatable(BaseObject.new(), PlayerAssetMarketTracker)
|
|
63
|
+
local self: PlayerAssetMarketTracker = setmetatable(BaseObject.new() :: any, PlayerAssetMarketTracker)
|
|
35
64
|
|
|
36
65
|
self._assetType = assert(assetType, "No assetType")
|
|
37
66
|
self._convertIds = assert(convertIds, "No convertIds")
|
|
@@ -44,9 +73,9 @@ function PlayerAssetMarketTracker.new(assetType: GameConfigAssetTypes.GameConfig
|
|
|
44
73
|
|
|
45
74
|
self._promptsOpenCount = self._maid:Add(ValueObject.new(0, "number"))
|
|
46
75
|
|
|
47
|
-
self.Purchased = self._maid:Add(Signal.new()) -- :Fire(id)
|
|
48
|
-
self.PromptClosed = self._maid:Add(Signal.new()) -- :Fire(id, isPurchased)
|
|
49
|
-
self.ShowPromptRequested = self._maid:Add(Signal.new()) -- :Fire(id)
|
|
76
|
+
self.Purchased = self._maid:Add(Signal.new() :: any) -- :Fire(id)
|
|
77
|
+
self.PromptClosed = self._maid:Add(Signal.new() :: any) -- :Fire(id, isPurchased)
|
|
78
|
+
self.ShowPromptRequested = self._maid:Add(Signal.new() :: any) -- :Fire(id)
|
|
50
79
|
|
|
51
80
|
self._maid:GiveTask(self.Purchased:Connect(function(id)
|
|
52
81
|
self._purchasedThisSession[id] = true
|
|
@@ -65,11 +94,15 @@ function PlayerAssetMarketTracker.new(assetType: GameConfigAssetTypes.GameConfig
|
|
|
65
94
|
self._maid:GiveTask(function()
|
|
66
95
|
while #self._pendingPurchasePromises > 0 do
|
|
67
96
|
local pending = table.remove(self._pendingPurchasePromises, #self._pendingPurchasePromises)
|
|
97
|
+
assert(pending, "Typechecking assertion")
|
|
98
|
+
|
|
68
99
|
pending:Reject()
|
|
69
100
|
end
|
|
70
101
|
|
|
71
102
|
while #self._pendingPromptOpenPromises > 0 do
|
|
72
103
|
local pending = table.remove(self._pendingPromptOpenPromises, #self._pendingPromptOpenPromises)
|
|
104
|
+
assert(pending, "Typechecking assertion")
|
|
105
|
+
|
|
73
106
|
pending:Reject()
|
|
74
107
|
end
|
|
75
108
|
end)
|
|
@@ -82,7 +115,7 @@ end
|
|
|
82
115
|
|
|
83
116
|
@return Observable<number>
|
|
84
117
|
]=]
|
|
85
|
-
function PlayerAssetMarketTracker
|
|
118
|
+
function PlayerAssetMarketTracker.ObservePromptOpenCount(self: PlayerAssetMarketTracker): Observable.Observable<number>
|
|
86
119
|
return self._promptsOpenCount:Observe()
|
|
87
120
|
end
|
|
88
121
|
|
|
@@ -92,7 +125,10 @@ end
|
|
|
92
125
|
@param idOrKey string | number
|
|
93
126
|
@return Observable<()>
|
|
94
127
|
]=]
|
|
95
|
-
function PlayerAssetMarketTracker
|
|
128
|
+
function PlayerAssetMarketTracker.ObserveAssetPurchased(
|
|
129
|
+
self: PlayerAssetMarketTracker,
|
|
130
|
+
idOrKey: string | number
|
|
131
|
+
): Observable.Observable<()>
|
|
96
132
|
assert(type(idOrKey) == "number" or type(idOrKey) == "string", "Bad idOrKey")
|
|
97
133
|
|
|
98
134
|
return Observable.new(function(sub)
|
|
@@ -132,7 +168,9 @@ end
|
|
|
132
168
|
|
|
133
169
|
@return GetOwnershipTracker
|
|
134
170
|
]=]
|
|
135
|
-
function PlayerAssetMarketTracker
|
|
171
|
+
function PlayerAssetMarketTracker.GetOwnershipTracker(
|
|
172
|
+
self: PlayerAssetMarketTracker
|
|
173
|
+
): PlayerAssetOwnershipTracker.PlayerAssetOwnershipTracker?
|
|
136
174
|
return self._ownershipTracker
|
|
137
175
|
end
|
|
138
176
|
|
|
@@ -143,7 +181,10 @@ end
|
|
|
143
181
|
@param idOrKey number | string
|
|
144
182
|
@return Promise<boolean>
|
|
145
183
|
]=]
|
|
146
|
-
function PlayerAssetMarketTracker
|
|
184
|
+
function PlayerAssetMarketTracker.PromisePromptPurchase(
|
|
185
|
+
self: PlayerAssetMarketTracker,
|
|
186
|
+
idOrKey: string | number
|
|
187
|
+
): Promise.Promise<boolean>
|
|
147
188
|
assert(type(idOrKey) == "number" or type(idOrKey) == "string", "Bad idOrKey")
|
|
148
189
|
|
|
149
190
|
local id = self._convertIds(idOrKey)
|
|
@@ -202,7 +243,7 @@ function PlayerAssetMarketTracker:PromisePromptPurchase(idOrKey: string | number
|
|
|
202
243
|
end
|
|
203
244
|
|
|
204
245
|
do
|
|
205
|
-
local promptOpenPromise = Promise.new()
|
|
246
|
+
local promptOpenPromise: Promise.Promise<boolean> = Promise.new()
|
|
206
247
|
self._pendingPromptOpenPromises[id] = promptOpenPromise
|
|
207
248
|
|
|
208
249
|
self._promptsOpenCount.Value = self._promptsOpenCount.Value + 1
|
|
@@ -215,7 +256,7 @@ function PlayerAssetMarketTracker:PromisePromptPurchase(idOrKey: string | number
|
|
|
215
256
|
end
|
|
216
257
|
|
|
217
258
|
-- Make sure to do promise here so we can't double-open prompts
|
|
218
|
-
local purchasePromise = Promise.new()
|
|
259
|
+
local purchasePromise: Promise.Promise<boolean> = Promise.new()
|
|
219
260
|
self._pendingPurchasePromises[id] = purchasePromise
|
|
220
261
|
|
|
221
262
|
purchasePromise:Finally(function()
|
|
@@ -235,7 +276,10 @@ end
|
|
|
235
276
|
|
|
236
277
|
@param ownershipTracker PlayerAssetOwnershipTracker
|
|
237
278
|
]=]
|
|
238
|
-
function PlayerAssetMarketTracker
|
|
279
|
+
function PlayerAssetMarketTracker.SetOwnershipTracker(
|
|
280
|
+
self: PlayerAssetMarketTracker,
|
|
281
|
+
ownershipTracker: PlayerAssetOwnershipTracker.PlayerAssetOwnershipTracker?
|
|
282
|
+
): ()
|
|
239
283
|
assert(type(ownershipTracker) == "table" or ownershipTracker == nil, "Bad ownershipTracker")
|
|
240
284
|
|
|
241
285
|
self._ownershipTracker = ownershipTracker
|
|
@@ -246,7 +290,7 @@ end
|
|
|
246
290
|
|
|
247
291
|
@return GameConfigAssetTypes
|
|
248
292
|
]=]
|
|
249
|
-
function PlayerAssetMarketTracker
|
|
293
|
+
function PlayerAssetMarketTracker.GetAssetType(self: PlayerAssetMarketTracker): GameConfigAssetTypes.GameConfigAssetType
|
|
250
294
|
return self._assetType
|
|
251
295
|
end
|
|
252
296
|
|
|
@@ -256,7 +300,10 @@ end
|
|
|
256
300
|
@param idOrKey string | number
|
|
257
301
|
@return boolean
|
|
258
302
|
]=]
|
|
259
|
-
function PlayerAssetMarketTracker
|
|
303
|
+
function PlayerAssetMarketTracker.HasPurchasedThisSession(
|
|
304
|
+
self: PlayerAssetMarketTracker,
|
|
305
|
+
idOrKey: string | number
|
|
306
|
+
): boolean
|
|
260
307
|
assert(type(idOrKey) == "number" or type(idOrKey) == "string", "idOrKey")
|
|
261
308
|
|
|
262
309
|
local id = self._convertIds(idOrKey)
|
|
@@ -277,7 +324,7 @@ end
|
|
|
277
324
|
|
|
278
325
|
@return boolean
|
|
279
326
|
]=]
|
|
280
|
-
function PlayerAssetMarketTracker
|
|
327
|
+
function PlayerAssetMarketTracker.IsPromptOpen(self: PlayerAssetMarketTracker): boolean
|
|
281
328
|
return self._promptsOpenCount.Value > 0
|
|
282
329
|
end
|
|
283
330
|
|
|
@@ -287,11 +334,15 @@ end
|
|
|
287
334
|
@param id number
|
|
288
335
|
@param isPurchased boolean
|
|
289
336
|
]=]
|
|
290
|
-
function PlayerAssetMarketTracker
|
|
337
|
+
function PlayerAssetMarketTracker.HandlePurchaseEvent(
|
|
338
|
+
self: PlayerAssetMarketTracker,
|
|
339
|
+
id: number,
|
|
340
|
+
isPurchased: boolean
|
|
341
|
+
): ()
|
|
291
342
|
assert(type(id) == "number", "Bad id")
|
|
292
343
|
assert(type(isPurchased) == "boolean", "Bad isPurchased")
|
|
293
344
|
|
|
294
|
-
local purchasePromise = self._pendingPurchasePromises[id] or Promise.new()
|
|
345
|
+
local purchasePromise: any = self._pendingPurchasePromises[id] or Promise.new()
|
|
295
346
|
|
|
296
347
|
if isPurchased then
|
|
297
348
|
self.Purchased:Fire(id)
|
|
@@ -305,10 +356,10 @@ end
|
|
|
305
356
|
|
|
306
357
|
@param id number
|
|
307
358
|
]=]
|
|
308
|
-
function PlayerAssetMarketTracker
|
|
359
|
+
function PlayerAssetMarketTracker.HandlePromptClosedEvent(self: PlayerAssetMarketTracker, id: number): ()
|
|
309
360
|
assert(type(id) == "number", "Bad id")
|
|
310
361
|
|
|
311
|
-
local promptOpenPromise = self._pendingPromptOpenPromises[id] or Promise.new()
|
|
362
|
+
local promptOpenPromise: any = self._pendingPromptOpenPromises[id] or Promise.new()
|
|
312
363
|
promptOpenPromise:Resolve()
|
|
313
364
|
end
|
|
314
365
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
See [PlayerProductManager] and [PlayerProductManagerClient]
|
|
3
4
|
|
|
@@ -13,11 +14,13 @@ local GameConfigAssetTypeUtils = require("GameConfigAssetTypeUtils")
|
|
|
13
14
|
local GameConfigAssetTypes = require("GameConfigAssetTypes")
|
|
14
15
|
local GameConfigDataService = require("GameConfigDataService")
|
|
15
16
|
local MarketplaceUtils = require("MarketplaceUtils")
|
|
17
|
+
local Observable = require("Observable")
|
|
16
18
|
local PlayerAssetMarketTracker = require("PlayerAssetMarketTracker")
|
|
17
19
|
local PlayerAssetMarketTrackerInterface = require("PlayerAssetMarketTrackerInterface")
|
|
18
20
|
local PlayerAssetOwnershipTracker = require("PlayerAssetOwnershipTracker")
|
|
19
21
|
local Promise = require("Promise")
|
|
20
22
|
local Rx = require("Rx")
|
|
23
|
+
local ServiceBag = require("ServiceBag")
|
|
21
24
|
local String = require("String")
|
|
22
25
|
local TieRealmService = require("TieRealmService")
|
|
23
26
|
|
|
@@ -25,6 +28,27 @@ local PlayerProductManagerBase = setmetatable({}, BaseObject)
|
|
|
25
28
|
PlayerProductManagerBase.ClassName = "PlayerProductManagerBase"
|
|
26
29
|
PlayerProductManagerBase.__index = PlayerProductManagerBase
|
|
27
30
|
|
|
31
|
+
export type PlayerProductManagerBase =
|
|
32
|
+
typeof(setmetatable(
|
|
33
|
+
{} :: {
|
|
34
|
+
_serviceBag: ServiceBag.ServiceBag,
|
|
35
|
+
_obj: Player,
|
|
36
|
+
_player: Player,
|
|
37
|
+
_tieRealmService: TieRealmService.TieRealmService,
|
|
38
|
+
_gameConfigDataService: GameConfigDataService.GameConfigDataService,
|
|
39
|
+
_configPicker: any,
|
|
40
|
+
_assetMarketTrackers: {
|
|
41
|
+
[GameConfigAssetTypes.GameConfigAssetType]: PlayerAssetMarketTracker.PlayerAssetMarketTracker,
|
|
42
|
+
},
|
|
43
|
+
_ownershipTrackers: {
|
|
44
|
+
[GameConfigAssetTypes.GameConfigAssetType]: PlayerAssetOwnershipTracker.PlayerAssetOwnershipTracker,
|
|
45
|
+
},
|
|
46
|
+
_observeNextNoPromptOpen: Observable.Observable<boolean>?,
|
|
47
|
+
},
|
|
48
|
+
{} :: typeof({ __index = PlayerProductManagerBase })
|
|
49
|
+
))
|
|
50
|
+
& BaseObject.BaseObject
|
|
51
|
+
|
|
28
52
|
--[=[
|
|
29
53
|
Constructs a new PlayerProductManagerBase, which provides helper methods for
|
|
30
54
|
the PlayerProductManager.
|
|
@@ -33,14 +57,14 @@ PlayerProductManagerBase.__index = PlayerProductManagerBase
|
|
|
33
57
|
@param serviceBag ServiceBag
|
|
34
58
|
@return PlayerProductManagerBase
|
|
35
59
|
]=]
|
|
36
|
-
function PlayerProductManagerBase.new(player, serviceBag)
|
|
37
|
-
local self = setmetatable(BaseObject.new(player), PlayerProductManagerBase)
|
|
60
|
+
function PlayerProductManagerBase.new(player: Player, serviceBag: ServiceBag.ServiceBag): PlayerProductManagerBase
|
|
61
|
+
local self: PlayerProductManagerBase = setmetatable(BaseObject.new(player) :: any, PlayerProductManagerBase)
|
|
38
62
|
|
|
39
63
|
self._player = assert(player, "No player")
|
|
40
64
|
|
|
41
65
|
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
42
|
-
self._tieRealmService = self._serviceBag:GetService(TieRealmService)
|
|
43
|
-
self._gameConfigDataService = self._serviceBag:GetService(GameConfigDataService)
|
|
66
|
+
self._tieRealmService = self._serviceBag:GetService(TieRealmService :: any)
|
|
67
|
+
self._gameConfigDataService = self._serviceBag:GetService(GameConfigDataService :: any)
|
|
44
68
|
|
|
45
69
|
self._configPicker = self._gameConfigDataService:GetConfigPicker()
|
|
46
70
|
|
|
@@ -78,7 +102,9 @@ function PlayerProductManagerBase.new(player, serviceBag)
|
|
|
78
102
|
MarketplaceService:PromptSubscriptionPurchase(self._player, subscriptionId)
|
|
79
103
|
end))
|
|
80
104
|
|
|
81
|
-
self._maid:GiveTask(membership.ShowPromptRequested:Connect(function(membershipType)
|
|
105
|
+
self._maid:GiveTask(membership.ShowPromptRequested:Connect(function(membershipType: any)
|
|
106
|
+
-- TODO: membershipType is not a number and checking is wrong
|
|
107
|
+
|
|
82
108
|
if membershipType == Enum.MembershipType.Premium then
|
|
83
109
|
MarketplaceService:PromptPremiumPurchase(self._player)
|
|
84
110
|
else
|
|
@@ -120,8 +146,8 @@ function PlayerProductManagerBase.new(player, serviceBag)
|
|
|
120
146
|
return self
|
|
121
147
|
end
|
|
122
148
|
|
|
123
|
-
function PlayerProductManagerBase
|
|
124
|
-
for assetType, assetMarketTracker in self._assetMarketTrackers do
|
|
149
|
+
function PlayerProductManagerBase.ExportMarketTrackers(self: PlayerProductManagerBase, parent)
|
|
150
|
+
for assetType: GameConfigAssetTypes.GameConfigAssetType, assetMarketTracker in self._assetMarketTrackers do
|
|
125
151
|
local folder = self._maid:Add(Instance.new("Folder"))
|
|
126
152
|
folder.Name = String.toCamelCase(GameConfigAssetTypeUtils.getPlural(assetType))
|
|
127
153
|
folder.Archivable = false
|
|
@@ -138,7 +164,7 @@ end
|
|
|
138
164
|
Gets the current player
|
|
139
165
|
@return Player
|
|
140
166
|
]=]
|
|
141
|
-
function PlayerProductManagerBase
|
|
167
|
+
function PlayerProductManagerBase.GetPlayer(self: PlayerProductManagerBase): Player
|
|
142
168
|
return self._obj
|
|
143
169
|
end
|
|
144
170
|
|
|
@@ -147,7 +173,7 @@ end
|
|
|
147
173
|
@param assetType GameConfigAssetType
|
|
148
174
|
@return PlayerAssetMarketTracker
|
|
149
175
|
]=]
|
|
150
|
-
function PlayerProductManagerBase
|
|
176
|
+
function PlayerProductManagerBase.IsOwnable(self: PlayerProductManagerBase, assetType): boolean
|
|
151
177
|
assert(GameConfigAssetTypeUtils.isAssetType(assetType), "Bad assetType")
|
|
152
178
|
|
|
153
179
|
return self._ownershipTrackers[assetType] ~= nil
|
|
@@ -158,8 +184,8 @@ end
|
|
|
158
184
|
|
|
159
185
|
@return boolean
|
|
160
186
|
]=]
|
|
161
|
-
function PlayerProductManagerBase
|
|
162
|
-
for _, assetTracker in self._assetMarketTrackers do
|
|
187
|
+
function PlayerProductManagerBase.IsPromptOpen(self: PlayerProductManagerBase): boolean
|
|
188
|
+
for _, assetTracker: any in self._assetMarketTrackers do
|
|
163
189
|
if assetTracker:IsPromptOpen() then
|
|
164
190
|
return true
|
|
165
191
|
end
|
|
@@ -173,18 +199,18 @@ end
|
|
|
173
199
|
|
|
174
200
|
@return Promise
|
|
175
201
|
]=]
|
|
176
|
-
function PlayerProductManagerBase
|
|
202
|
+
function PlayerProductManagerBase.PromisePlayerPromptClosed(self: PlayerProductManagerBase): Promise.Promise<()>
|
|
177
203
|
if not self:IsPromptOpen() then
|
|
178
204
|
return Promise.resolved()
|
|
179
205
|
end
|
|
180
206
|
|
|
181
207
|
if self._observeNextNoPromptOpen then
|
|
182
|
-
return Rx.toPromise(self._observeNextNoPromptOpen)
|
|
208
|
+
return Rx.toPromise(self._observeNextNoPromptOpen :: any)
|
|
183
209
|
end
|
|
184
210
|
|
|
185
211
|
local observeOpenCounts = {}
|
|
186
212
|
|
|
187
|
-
for assetType, assetTracker in self._assetMarketTrackers do
|
|
213
|
+
for assetType, assetTracker: any in self._assetMarketTrackers do
|
|
188
214
|
observeOpenCounts[assetType] = assetTracker:ObservePromptOpenCount()
|
|
189
215
|
end
|
|
190
216
|
|
|
@@ -197,15 +223,15 @@ function PlayerProductManagerBase:PromisePlayerPromptClosed()
|
|
|
197
223
|
end
|
|
198
224
|
|
|
199
225
|
return true
|
|
200
|
-
end),
|
|
226
|
+
end) :: any,
|
|
201
227
|
Rx.where(function(value)
|
|
202
228
|
return value
|
|
203
|
-
end),
|
|
204
|
-
Rx.distinct(),
|
|
205
|
-
Rx.share(),
|
|
206
|
-
})
|
|
229
|
+
end) :: any,
|
|
230
|
+
Rx.distinct() :: any,
|
|
231
|
+
Rx.share() :: any,
|
|
232
|
+
}) :: any
|
|
207
233
|
|
|
208
|
-
return Rx.toPromise(self._observeNextNoPromptOpen)
|
|
234
|
+
return Rx.toPromise(self._observeNextNoPromptOpen :: any)
|
|
209
235
|
end
|
|
210
236
|
|
|
211
237
|
--[=[
|
|
@@ -214,7 +240,10 @@ end
|
|
|
214
240
|
@param assetType GameConfigAssetType
|
|
215
241
|
@return PlayerAssetMarketTracker
|
|
216
242
|
]=]
|
|
217
|
-
function PlayerProductManagerBase
|
|
243
|
+
function PlayerProductManagerBase.GetAssetTrackerOrError(
|
|
244
|
+
self: PlayerProductManagerBase,
|
|
245
|
+
assetType: GameConfigAssetTypes.GameConfigAssetType
|
|
246
|
+
): PlayerAssetMarketTracker.PlayerAssetMarketTracker
|
|
218
247
|
assert(GameConfigAssetTypeUtils.isAssetType(assetType), "Bad assetType")
|
|
219
248
|
|
|
220
249
|
local assetTracker = self._assetMarketTrackers[assetType]
|
|
@@ -230,7 +259,10 @@ end
|
|
|
230
259
|
@param assetType GameConfigAssetType
|
|
231
260
|
@return PlayerAssetMarketTracker
|
|
232
261
|
]=]
|
|
233
|
-
function PlayerProductManagerBase
|
|
262
|
+
function PlayerProductManagerBase.GetOwnershipTrackerOrError(
|
|
263
|
+
self: PlayerProductManagerBase,
|
|
264
|
+
assetType: GameConfigAssetTypes.GameConfigAssetType
|
|
265
|
+
): PlayerAssetOwnershipTracker.PlayerAssetOwnershipTracker
|
|
234
266
|
assert(GameConfigAssetTypeUtils.isAssetType(assetType), "Bad assetType")
|
|
235
267
|
|
|
236
268
|
local assetTracker = self._ownershipTrackers[assetType]
|
|
@@ -240,7 +272,10 @@ function PlayerProductManagerBase:GetOwnershipTrackerOrError(assetType)
|
|
|
240
272
|
return assetTracker
|
|
241
273
|
end
|
|
242
274
|
|
|
243
|
-
function PlayerProductManagerBase
|
|
275
|
+
function PlayerProductManagerBase._addOwnershipTracker(
|
|
276
|
+
self: PlayerProductManagerBase,
|
|
277
|
+
assetType: GameConfigAssetTypes.GameConfigAssetType
|
|
278
|
+
): PlayerAssetOwnershipTracker.PlayerAssetOwnershipTracker
|
|
244
279
|
assert(GameConfigAssetTypeUtils.isAssetType(assetType), "Bad assetType")
|
|
245
280
|
assert(not self._ownershipTrackers[assetType], "Already have ownership tracker")
|
|
246
281
|
|
|
@@ -255,7 +290,10 @@ function PlayerProductManagerBase:_addOwnershipTracker(assetType)
|
|
|
255
290
|
return ownershipTracker
|
|
256
291
|
end
|
|
257
292
|
|
|
258
|
-
function PlayerProductManagerBase
|
|
293
|
+
function PlayerProductManagerBase._addAssetTracker(
|
|
294
|
+
self: PlayerProductManagerBase,
|
|
295
|
+
assetType: GameConfigAssetTypes.GameConfigAssetType
|
|
296
|
+
): PlayerAssetMarketTracker.PlayerAssetMarketTracker
|
|
259
297
|
assert(GameConfigAssetTypeUtils.isAssetType(assetType), "Bad assetType")
|
|
260
298
|
assert(not self._assetMarketTrackers[assetType], "Already have tracker")
|
|
261
299
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!nonstrict
|
|
1
2
|
--[[
|
|
2
3
|
@class ServerMain
|
|
3
4
|
]]
|
|
@@ -19,7 +20,7 @@ serviceBag:GetService(require("GameConfigService")):AddAsset("FrogOnHead", 45565
|
|
|
19
20
|
|
|
20
21
|
local GameConfigAssetTypes = require("GameConfigAssetTypes")
|
|
21
22
|
|
|
22
|
-
local function makePrompt(assetType, idOrKey, cframe)
|
|
23
|
+
local function makePrompt(assetType: GameConfigAssetTypes.GameConfigAssetType, idOrKey: number | string, cframe: CFrame)
|
|
23
24
|
assert(type(idOrKey) == "number" or type(idOrKey) == "string", "Bad idOrKey")
|
|
24
25
|
|
|
25
26
|
local promptPart = Instance.new("Part")
|