@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 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.7",
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": "^14.20.5",
31
- "@quenty/avatareditorutils": "^7.25.6",
32
- "@quenty/baseobject": "^10.9.0",
33
- "@quenty/binder": "^14.25.6",
34
- "@quenty/brio": "^14.20.4",
35
- "@quenty/cmdrservice": "^13.29.7",
36
- "@quenty/enumutils": "^3.4.2",
37
- "@quenty/gameconfig": "^12.33.7",
38
- "@quenty/instanceutils": "^13.20.5",
39
- "@quenty/loader": "^10.9.0",
40
- "@quenty/maid": "^3.5.0",
41
- "@quenty/marketplaceutils": "^11.13.3",
42
- "@quenty/observablecollection": "^12.24.6",
43
- "@quenty/playerbinder": "^14.25.6",
44
- "@quenty/playerutils": "^8.21.6",
45
- "@quenty/promise": "^10.12.3",
46
- "@quenty/promisemaid": "^5.12.3",
47
- "@quenty/receiptprocessing": "^7.23.6",
48
- "@quenty/remoting": "^12.21.5",
49
- "@quenty/rx": "^13.20.3",
50
- "@quenty/rxbinderutils": "^14.25.6",
51
- "@quenty/servicebag": "^11.13.3",
52
- "@quenty/signal": "^7.11.2",
53
- "@quenty/statestack": "^14.22.6",
54
- "@quenty/string": "^3.3.3",
55
- "@quenty/table": "^3.8.0",
56
- "@quenty/tie": "^10.26.6",
57
- "@quenty/valueobject": "^13.21.6"
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": "ed3284dd547d8f9922043ca68ed16bf3769806bb"
59
+ "gitHead": "90de6ebb6e0cb5e6798e08b312cb1864c1d3354c"
60
60
  }
@@ -1,3 +1,4 @@
1
+ --!nonstrict
1
2
  --[=[
2
3
  This service provides an interface to purchase produces, assets, and other
3
4
  marketplace items. This listens to events, handles requests between server and
@@ -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
- function PlayerProductManagerClient.new(obj, serviceBag)
27
- local self = setmetatable(PlayerProductManagerBase.new(obj, serviceBag), PlayerProductManagerClient)
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
- self._avatarEditorInventoryServiceClient = self._serviceBag:GetService(AvatarEditorInventoryServiceClient)
30
- self._catalogSearchServiceCache = self._serviceBag:GetService(CatalogSearchServiceCache)
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:GetPlayer()
73
+ function PlayerProductManagerClient.GetPlayer(self: PlayerProductManagerClient): Player
56
74
  return self._obj
57
75
  end
58
76
 
59
- function PlayerProductManagerClient:_setupAssetTracker()
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:_setupMembershipTracker()
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
- tracker:HandlePromptClosedEvent(Enum.MembershipType.Premium)
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(Enum.MembershipType.Premium, self._obj.MembershipType == true)
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:_setupSubscriptionTracker()
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:_connectBulkPurchaseMarketplace()
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:_setupProductTracker()
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:_connectGamePassTracker()
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:_setupBundleTracker()
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, Enum.AvatarItemType.Bundle)
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:_promiseBulkOwnsAssetQuery(assetId)
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 = EnumUtils.toEnum(Enum.AvatarAssetType, itemDetails.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:_promiseBulkOwnsBundleQuery(bundleId)
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("PlayerProductManager", PlayerProductManagerClient)
276
+ return Binder.new(
277
+ "PlayerProductManager",
278
+ PlayerProductManagerClient :: any
279
+ ) :: Binder.Binder<PlayerProductManagerClient>
@@ -1,3 +1,4 @@
1
+ --!nonstrict
1
2
  --[=[
2
3
  @class GameProductCmdrService
3
4
  ]=]
@@ -1,3 +1,4 @@
1
+ --!nonstrict
1
2
  --[=[
2
3
  This service provides an interface to purchase produces, assets, and other
3
4
  marketplace items. This listens to events, handles requests between server and
@@ -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 = setmetatable(PlayerProductManagerBase.new(player, serviceBag), PlayerProductManager)
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:_setupRemoting()
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:_setupAssetTracker()
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:_setupProductTracker()
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:_setupPassTracker()
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:_setupMembershipTracker()
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:_setupSubscriptionTracker()
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:_setupBundleTracker()
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
+ --!nonstrict
1
2
  --[=[
2
3
  @class PlayerAssetMarketTrackerInterface
3
4
  ]=]
@@ -1,3 +1,4 @@
1
+ --!nonstrict
1
2
  --[=[
2
3
  @class PlayerProductManagerInterface
3
4
  ]=]
@@ -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
- function PlayerAssetOwnershipTracker.new(player, configPicker, assetType, marketTracker)
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(assetType: GameConfigAssetTypes.GameConfigAssetType, convertIds, observeIdsBrio)
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:ObservePromptOpenCount(): Observable.Observable<number>
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:ObserveAssetPurchased(idOrKey: string | number): Observable.Observable<()>
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:GetOwnershipTracker()
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:PromisePromptPurchase(idOrKey: string | number)
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:SetOwnershipTracker(ownershipTracker)
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:GetAssetType(): GameConfigAssetTypes.GameConfigAssetType
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:HasPurchasedThisSession(idOrKey: string | number)
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:IsPromptOpen(): boolean
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:HandlePurchaseEvent(id: number, isPurchased: boolean)
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:HandlePromptClosedEvent(id: number)
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:ExportMarketTrackers(parent)
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:GetPlayer(): Player
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:IsOwnable(assetType): boolean
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:IsPromptOpen(): boolean
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:PromisePlayerPromptClosed()
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:GetAssetTrackerOrError(assetType)
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:GetOwnershipTrackerOrError(assetType)
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:_addOwnershipTracker(assetType)
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:_addAssetTracker(assetType)
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 ClientMain
3
4
  ]]
@@ -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")