@quenty/gameproductservice 14.34.8-canary.ba2274e.0 → 14.34.8

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,7 +3,7 @@
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.ba2274e.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/gameproductservice@14.34.7...@quenty/gameproductservice@14.34.8-canary.ba2274e.0) (2026-01-02)
6
+ ## [14.34.8](https://github.com/Quenty/NevermoreEngine/compare/@quenty/gameproductservice@14.34.7...@quenty/gameproductservice@14.34.8) (2026-01-03)
7
7
 
8
8
  **Note:** Version bump only for package @quenty/gameproductservice
9
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/gameproductservice",
3
- "version": "14.34.8-canary.ba2274e.0",
3
+ "version": "14.34.8",
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.7-canary.ba2274e.0",
34
- "@quenty/brio": "14.20.4",
35
- "@quenty/cmdrservice": "13.29.7",
36
- "@quenty/enumutils": "3.4.2",
37
- "@quenty/gameconfig": "12.33.8-canary.ba2274e.0",
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.7-canary.ba2274e.0",
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.7-canary.ba2274e.0",
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",
31
+ "@quenty/avatareditorutils": "^7.25.7",
32
+ "@quenty/baseobject": "^10.9.1",
33
+ "@quenty/binder": "^14.25.7",
34
+ "@quenty/brio": "^14.20.5",
35
+ "@quenty/cmdrservice": "^13.29.8",
36
+ "@quenty/enumutils": "^3.4.3",
37
+ "@quenty/gameconfig": "^12.33.8",
38
+ "@quenty/instanceutils": "^13.20.6",
39
+ "@quenty/loader": "^10.9.1",
40
+ "@quenty/maid": "^3.5.1",
41
+ "@quenty/marketplaceutils": "^11.13.4",
42
+ "@quenty/observablecollection": "^12.24.7",
43
+ "@quenty/playerbinder": "^14.25.7",
44
+ "@quenty/playerutils": "^8.21.7",
45
+ "@quenty/promise": "^10.12.4",
46
+ "@quenty/promisemaid": "^5.12.4",
47
+ "@quenty/receiptprocessing": "^7.23.7",
48
+ "@quenty/remoting": "^12.21.6",
49
+ "@quenty/rx": "^13.20.4",
50
+ "@quenty/rxbinderutils": "^14.25.7",
51
+ "@quenty/servicebag": "^11.13.4",
52
+ "@quenty/signal": "^7.11.3",
53
+ "@quenty/statestack": "^14.22.7",
54
+ "@quenty/string": "^3.3.4",
55
+ "@quenty/table": "^3.8.0",
56
+ "@quenty/tie": "^10.26.7",
57
+ "@quenty/valueobject": "^13.21.7"
58
58
  },
59
- "gitHead": "ba2274ec070356518a157d80f912b05de9f74451"
59
+ "gitHead": "44e41814ddc3c14c3879320a10ed2d8e88103a4c"
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
@@ -24,11 +25,27 @@ local PlayerProductManagerClient = setmetatable({}, PlayerProductManagerBase)
24
25
  PlayerProductManagerClient.ClassName = "PlayerProductManagerClient"
25
26
  PlayerProductManagerClient.__index = PlayerProductManagerClient
26
27
 
27
- function PlayerProductManagerClient.new(obj, serviceBag: ServiceBag.ServiceBag)
28
- 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,
29
35
 
30
- self._avatarEditorInventoryServiceClient = self._serviceBag:GetService(AvatarEditorInventoryServiceClient)
31
- 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)
32
49
 
33
50
  if self._obj == Players.LocalPlayer then
34
51
  self._remoting = self._maid:Add(Remoting.new(self._obj, "PlayerProductManager", Remoting.Realms.CLIENT))
@@ -53,11 +70,11 @@ end
53
70
  Gets the current player
54
71
  @return Player
55
72
  ]=]
56
- function PlayerProductManagerClient:GetPlayer()
73
+ function PlayerProductManagerClient.GetPlayer(self: PlayerProductManagerClient): Player
57
74
  return self._obj
58
75
  end
59
76
 
60
- function PlayerProductManagerClient:_setupAssetTracker()
77
+ function PlayerProductManagerClient._setupAssetTracker(self: PlayerProductManagerClient): ()
61
78
  local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.ASSET)
62
79
  local assetOwnership = assert(tracker:GetOwnershipTracker(), "Missing ownershipTracker on client")
63
80
 
@@ -74,14 +91,18 @@ function PlayerProductManagerClient:_setupAssetTracker()
74
91
  end))
75
92
  end
76
93
 
77
- function PlayerProductManagerClient:_setupMembershipTracker()
94
+ function PlayerProductManagerClient._setupMembershipTracker(self: PlayerProductManagerClient): ()
78
95
  local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.MEMBERSHIP)
79
96
 
80
97
  self._maid:GiveTask(MarketplaceService.PromptPremiumPurchaseFinished:Connect(function()
81
- tracker:HandlePromptClosedEvent(Enum.MembershipType.Premium)
98
+ -- TODO: Fix typing, these expect a number
99
+ tracker:HandlePromptClosedEvent(Enum.MembershipType.Premium :: any)
82
100
 
83
101
  -- Not great behavior but whatever
84
- 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
+ )
85
106
  end))
86
107
 
87
108
  -- I think this only fires on the server...
@@ -94,7 +115,7 @@ function PlayerProductManagerClient:_setupMembershipTracker()
94
115
  end))
95
116
  end
96
117
 
97
- function PlayerProductManagerClient:_setupSubscriptionTracker()
118
+ function PlayerProductManagerClient._setupSubscriptionTracker(self: PlayerProductManagerClient): ()
98
119
  local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.SUBSCRIPTION)
99
120
 
100
121
  -- Main event
@@ -127,7 +148,7 @@ function PlayerProductManagerClient:_setupSubscriptionTracker()
127
148
  end))
128
149
  end
129
150
 
130
- function PlayerProductManagerClient:_connectBulkPurchaseMarketplace()
151
+ function PlayerProductManagerClient._connectBulkPurchaseMarketplace(self: PlayerProductManagerClient): ()
131
152
  self._maid:GiveTask(MarketplaceService.PromptBulkPurchaseFinished:Connect(function(player, status, results)
132
153
  if player ~= self._obj then
133
154
  return
@@ -161,7 +182,7 @@ function PlayerProductManagerClient:_connectBulkPurchaseMarketplace()
161
182
  end))
162
183
  end
163
184
 
164
- function PlayerProductManagerClient:_setupProductTracker()
185
+ function PlayerProductManagerClient._setupProductTracker(self: PlayerProductManagerClient): ()
165
186
  local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.PRODUCT)
166
187
 
167
188
  self._maid:GiveTask(
@@ -185,7 +206,7 @@ function PlayerProductManagerClient:_setupProductTracker()
185
206
  end))
186
207
  end
187
208
 
188
- function PlayerProductManagerClient:_connectGamePassTracker()
209
+ function PlayerProductManagerClient._connectGamePassTracker(self: PlayerProductManagerClient): ()
189
210
  local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.PASS)
190
211
 
191
212
  self._maid:GiveTask(
@@ -202,13 +223,13 @@ function PlayerProductManagerClient:_connectGamePassTracker()
202
223
  )
203
224
  end
204
225
 
205
- function PlayerProductManagerClient:_setupBundleTracker()
226
+ function PlayerProductManagerClient._setupBundleTracker(self: PlayerProductManagerClient): ()
206
227
  local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.BUNDLE)
207
228
 
208
229
  local bundleOwnership = assert(tracker:GetOwnershipTracker(), "Missing ownershipTracker on client")
209
230
 
210
231
  bundleOwnership:SetQueryOwnershipCallback(function(assetId)
211
- return self:_promiseBulkOwnsBundleQuery(assetId, Enum.AvatarItemType.Bundle)
232
+ return self:_promiseBulkOwnsBundleQuery(assetId)
212
233
  end)
213
234
 
214
235
  self._maid:GiveTask(MarketplaceService.PromptBundlePurchaseFinished:Connect(function(player, bundleId, isPurchased)
@@ -221,7 +242,7 @@ function PlayerProductManagerClient:_setupBundleTracker()
221
242
  end))
222
243
  end
223
244
 
224
- function PlayerProductManagerClient:_promiseBulkOwnsAssetQuery(assetId)
245
+ function PlayerProductManagerClient._promiseBulkOwnsAssetQuery(self: PlayerProductManagerClient, assetId)
225
246
  if self._avatarEditorInventoryServiceClient:IsInventoryAccessAllowed() then
226
247
  -- When scrolling through a ton of entries in the avatar editor we want to query
227
248
  -- this is typically faster. We really hope we aren't the Roblox account.
@@ -230,7 +251,8 @@ function PlayerProductManagerClient:_promiseBulkOwnsAssetQuery(assetId)
230
251
  :Then(function(itemDetails)
231
252
  -- https://devforum.roblox.com/t/avatareditorservicegetitemdetails-returns-ownership-where-as-avatareditorservicegetbatchitemdetails-does-not/3257431
232
253
 
233
- local assetType = EnumUtils.toEnum(Enum.AvatarAssetType, itemDetails.AssetType)
254
+ local assetType: Enum.AvatarAssetType? =
255
+ EnumUtils.toEnum(Enum.AvatarAssetType, itemDetails.AssetType) :: any
234
256
  if not assetType then
235
257
  -- TODO: Fallback to standard query?
236
258
  return Promise.rejected("Failed to get assetType")
@@ -247,8 +269,11 @@ function PlayerProductManagerClient:_promiseBulkOwnsAssetQuery(assetId)
247
269
  return MarketplaceUtils.promisePlayerOwnsAsset(self._player, assetId)
248
270
  end
249
271
 
250
- function PlayerProductManagerClient:_promiseBulkOwnsBundleQuery(bundleId)
272
+ function PlayerProductManagerClient._promiseBulkOwnsBundleQuery(self: PlayerProductManagerClient, bundleId: number)
251
273
  return MarketplaceUtils.promisePlayerOwnsBundle(self._player, bundleId)
252
274
  end
253
275
 
254
- 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
 
@@ -23,6 +24,16 @@ local PlayerProductManager = setmetatable({}, PlayerProductManagerBase)
23
24
  PlayerProductManager.ClassName = "PlayerProductManager"
24
25
  PlayerProductManager.__index = PlayerProductManager
25
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
+
26
37
  --[=[
27
38
  Managers players products and purchase state. Should be retrieved via binder.
28
39
 
@@ -30,8 +41,9 @@ PlayerProductManager.__index = PlayerProductManager
30
41
  @param serviceBag ServiceBag
31
42
  @return PlayerProductManager
32
43
  ]=]
33
- function PlayerProductManager.new(player, serviceBag: ServiceBag.ServiceBag)
34
- 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)
35
47
 
36
48
  self._serviceBag = assert(serviceBag, "No serviceBag")
37
49
  self._receiptProcessingService = self._serviceBag:GetService(ReceiptProcessingService)
@@ -55,11 +67,11 @@ function PlayerProductManager.new(player, serviceBag: ServiceBag.ServiceBag)
55
67
  return self
56
68
  end
57
69
 
58
- function PlayerProductManager:_setupRemoting()
70
+ function PlayerProductManager._setupRemoting(self: PlayerProductManager): ()
59
71
  self._remoting = self._maid:Add(Remoting.Server.new(self._obj, "PlayerProductManager", Remoting.Realms.SERVER))
60
72
  end
61
73
 
62
- function PlayerProductManager:_setupAssetTracker()
74
+ function PlayerProductManager._setupAssetTracker(self: PlayerProductManager): ()
63
75
  local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.ASSET)
64
76
 
65
77
  self._maid:GiveTask(self._remoting.AssetPromptPurchaseFinished:Connect(function(player, assetId, isPurchased)
@@ -73,7 +85,7 @@ function PlayerProductManager:_setupAssetTracker()
73
85
  end))
74
86
  end
75
87
 
76
- function PlayerProductManager:_setupProductTracker()
88
+ function PlayerProductManager._setupProductTracker(self: PlayerProductManager): ()
77
89
  local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.PRODUCT)
78
90
 
79
91
  -- Source of truth for purchase is here
@@ -105,7 +117,7 @@ function PlayerProductManager:_setupProductTracker()
105
117
  )
106
118
  end
107
119
 
108
- function PlayerProductManager:_setupPassTracker()
120
+ function PlayerProductManager._setupPassTracker(self: PlayerProductManager): ()
109
121
  local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.PASS)
110
122
 
111
123
  self._maid:GiveTask(self._remoting.PromptGamePassPurchaseFinished:Connect(function(player, gamePassId, isPurchased)
@@ -119,7 +131,7 @@ function PlayerProductManager:_setupPassTracker()
119
131
  end))
120
132
  end
121
133
 
122
- function PlayerProductManager:_setupMembershipTracker()
134
+ function PlayerProductManager._setupMembershipTracker(self: PlayerProductManager): ()
123
135
  local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.MEMBERSHIP)
124
136
 
125
137
  self._maid:GiveTask(Players.PlayerMembershipChanged:Connect(function(player)
@@ -131,7 +143,7 @@ function PlayerProductManager:_setupMembershipTracker()
131
143
  end))
132
144
  end
133
145
 
134
- function PlayerProductManager:_setupSubscriptionTracker()
146
+ function PlayerProductManager._setupSubscriptionTracker(self: PlayerProductManager): ()
135
147
  self._remoting.UserSubscriptionStatusChanged:DeclareEvent()
136
148
 
137
149
  local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.SUBSCRIPTION)
@@ -164,7 +176,7 @@ function PlayerProductManager:_setupSubscriptionTracker()
164
176
  end))
165
177
  end
166
178
 
167
- function PlayerProductManager:_setupBundleTracker()
179
+ function PlayerProductManager._setupBundleTracker(self: PlayerProductManager): ()
168
180
  local tracker = self:GetAssetTrackerOrError(GameConfigAssetTypes.BUNDLE)
169
181
 
170
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,6 +14,7 @@ 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")
@@ -26,6 +28,27 @@ local PlayerProductManagerBase = setmetatable({}, BaseObject)
26
28
  PlayerProductManagerBase.ClassName = "PlayerProductManagerBase"
27
29
  PlayerProductManagerBase.__index = PlayerProductManagerBase
28
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
+
29
52
  --[=[
30
53
  Constructs a new PlayerProductManagerBase, which provides helper methods for
31
54
  the PlayerProductManager.
@@ -34,14 +57,14 @@ PlayerProductManagerBase.__index = PlayerProductManagerBase
34
57
  @param serviceBag ServiceBag
35
58
  @return PlayerProductManagerBase
36
59
  ]=]
37
- function PlayerProductManagerBase.new(player, serviceBag: ServiceBag.ServiceBag)
38
- 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)
39
62
 
40
63
  self._player = assert(player, "No player")
41
64
 
42
65
  self._serviceBag = assert(serviceBag, "No serviceBag")
43
- self._tieRealmService = self._serviceBag:GetService(TieRealmService)
44
- self._gameConfigDataService = self._serviceBag:GetService(GameConfigDataService)
66
+ self._tieRealmService = self._serviceBag:GetService(TieRealmService :: any)
67
+ self._gameConfigDataService = self._serviceBag:GetService(GameConfigDataService :: any)
45
68
 
46
69
  self._configPicker = self._gameConfigDataService:GetConfigPicker()
47
70
 
@@ -79,7 +102,9 @@ function PlayerProductManagerBase.new(player, serviceBag: ServiceBag.ServiceBag)
79
102
  MarketplaceService:PromptSubscriptionPurchase(self._player, subscriptionId)
80
103
  end))
81
104
 
82
- 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
+
83
108
  if membershipType == Enum.MembershipType.Premium then
84
109
  MarketplaceService:PromptPremiumPurchase(self._player)
85
110
  else
@@ -121,8 +146,8 @@ function PlayerProductManagerBase.new(player, serviceBag: ServiceBag.ServiceBag)
121
146
  return self
122
147
  end
123
148
 
124
- function PlayerProductManagerBase:ExportMarketTrackers(parent)
125
- for assetType, assetMarketTracker in self._assetMarketTrackers do
149
+ function PlayerProductManagerBase.ExportMarketTrackers(self: PlayerProductManagerBase, parent)
150
+ for assetType: GameConfigAssetTypes.GameConfigAssetType, assetMarketTracker in self._assetMarketTrackers do
126
151
  local folder = self._maid:Add(Instance.new("Folder"))
127
152
  folder.Name = String.toCamelCase(GameConfigAssetTypeUtils.getPlural(assetType))
128
153
  folder.Archivable = false
@@ -139,7 +164,7 @@ end
139
164
  Gets the current player
140
165
  @return Player
141
166
  ]=]
142
- function PlayerProductManagerBase:GetPlayer(): Player
167
+ function PlayerProductManagerBase.GetPlayer(self: PlayerProductManagerBase): Player
143
168
  return self._obj
144
169
  end
145
170
 
@@ -148,7 +173,7 @@ end
148
173
  @param assetType GameConfigAssetType
149
174
  @return PlayerAssetMarketTracker
150
175
  ]=]
151
- function PlayerProductManagerBase:IsOwnable(assetType): boolean
176
+ function PlayerProductManagerBase.IsOwnable(self: PlayerProductManagerBase, assetType): boolean
152
177
  assert(GameConfigAssetTypeUtils.isAssetType(assetType), "Bad assetType")
153
178
 
154
179
  return self._ownershipTrackers[assetType] ~= nil
@@ -159,8 +184,8 @@ end
159
184
 
160
185
  @return boolean
161
186
  ]=]
162
- function PlayerProductManagerBase:IsPromptOpen(): boolean
163
- for _, assetTracker in self._assetMarketTrackers do
187
+ function PlayerProductManagerBase.IsPromptOpen(self: PlayerProductManagerBase): boolean
188
+ for _, assetTracker: any in self._assetMarketTrackers do
164
189
  if assetTracker:IsPromptOpen() then
165
190
  return true
166
191
  end
@@ -174,18 +199,18 @@ end
174
199
 
175
200
  @return Promise
176
201
  ]=]
177
- function PlayerProductManagerBase:PromisePlayerPromptClosed()
202
+ function PlayerProductManagerBase.PromisePlayerPromptClosed(self: PlayerProductManagerBase): Promise.Promise<()>
178
203
  if not self:IsPromptOpen() then
179
204
  return Promise.resolved()
180
205
  end
181
206
 
182
207
  if self._observeNextNoPromptOpen then
183
- return Rx.toPromise(self._observeNextNoPromptOpen)
208
+ return Rx.toPromise(self._observeNextNoPromptOpen :: any)
184
209
  end
185
210
 
186
211
  local observeOpenCounts = {}
187
212
 
188
- for assetType, assetTracker in self._assetMarketTrackers do
213
+ for assetType, assetTracker: any in self._assetMarketTrackers do
189
214
  observeOpenCounts[assetType] = assetTracker:ObservePromptOpenCount()
190
215
  end
191
216
 
@@ -198,15 +223,15 @@ function PlayerProductManagerBase:PromisePlayerPromptClosed()
198
223
  end
199
224
 
200
225
  return true
201
- end),
226
+ end) :: any,
202
227
  Rx.where(function(value)
203
228
  return value
204
- end),
205
- Rx.distinct(),
206
- Rx.share(),
207
- })
229
+ end) :: any,
230
+ Rx.distinct() :: any,
231
+ Rx.share() :: any,
232
+ }) :: any
208
233
 
209
- return Rx.toPromise(self._observeNextNoPromptOpen)
234
+ return Rx.toPromise(self._observeNextNoPromptOpen :: any)
210
235
  end
211
236
 
212
237
  --[=[
@@ -215,7 +240,10 @@ end
215
240
  @param assetType GameConfigAssetType
216
241
  @return PlayerAssetMarketTracker
217
242
  ]=]
218
- function PlayerProductManagerBase:GetAssetTrackerOrError(assetType)
243
+ function PlayerProductManagerBase.GetAssetTrackerOrError(
244
+ self: PlayerProductManagerBase,
245
+ assetType: GameConfigAssetTypes.GameConfigAssetType
246
+ ): PlayerAssetMarketTracker.PlayerAssetMarketTracker
219
247
  assert(GameConfigAssetTypeUtils.isAssetType(assetType), "Bad assetType")
220
248
 
221
249
  local assetTracker = self._assetMarketTrackers[assetType]
@@ -231,7 +259,10 @@ end
231
259
  @param assetType GameConfigAssetType
232
260
  @return PlayerAssetMarketTracker
233
261
  ]=]
234
- function PlayerProductManagerBase:GetOwnershipTrackerOrError(assetType)
262
+ function PlayerProductManagerBase.GetOwnershipTrackerOrError(
263
+ self: PlayerProductManagerBase,
264
+ assetType: GameConfigAssetTypes.GameConfigAssetType
265
+ ): PlayerAssetOwnershipTracker.PlayerAssetOwnershipTracker
235
266
  assert(GameConfigAssetTypeUtils.isAssetType(assetType), "Bad assetType")
236
267
 
237
268
  local assetTracker = self._ownershipTrackers[assetType]
@@ -241,7 +272,10 @@ function PlayerProductManagerBase:GetOwnershipTrackerOrError(assetType)
241
272
  return assetTracker
242
273
  end
243
274
 
244
- function PlayerProductManagerBase:_addOwnershipTracker(assetType)
275
+ function PlayerProductManagerBase._addOwnershipTracker(
276
+ self: PlayerProductManagerBase,
277
+ assetType: GameConfigAssetTypes.GameConfigAssetType
278
+ ): PlayerAssetOwnershipTracker.PlayerAssetOwnershipTracker
245
279
  assert(GameConfigAssetTypeUtils.isAssetType(assetType), "Bad assetType")
246
280
  assert(not self._ownershipTrackers[assetType], "Already have ownership tracker")
247
281
 
@@ -256,7 +290,10 @@ function PlayerProductManagerBase:_addOwnershipTracker(assetType)
256
290
  return ownershipTracker
257
291
  end
258
292
 
259
- function PlayerProductManagerBase:_addAssetTracker(assetType)
293
+ function PlayerProductManagerBase._addAssetTracker(
294
+ self: PlayerProductManagerBase,
295
+ assetType: GameConfigAssetTypes.GameConfigAssetType
296
+ ): PlayerAssetMarketTracker.PlayerAssetMarketTracker
260
297
  assert(GameConfigAssetTypeUtils.isAssetType(assetType), "Bad assetType")
261
298
  assert(not self._assetMarketTrackers[assetType], "Already have tracker")
262
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")