@quenty/gameproductservice 3.3.1 → 3.4.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,17 @@
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
+ # [3.4.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/gameproductservice@3.3.1...@quenty/gameproductservice@3.4.0) (2022-07-31)
7
+
8
+
9
+ ### Features
10
+
11
+ * API calls in GameProductService support passids or string keys to retrieve the passes. ([083170e](https://github.com/Quenty/NevermoreEngine/commit/083170e92bf2e71628edd17bf526d4b0936fe1a9))
12
+
13
+
14
+
15
+
16
+
6
17
  ## [3.3.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/gameproductservice@3.3.0...@quenty/gameproductservice@3.3.1) (2022-07-19)
7
18
 
8
19
  **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": "3.3.1",
3
+ "version": "3.4.0",
4
4
  "description": "Generalized monetization system for handling products and purchases correctly.",
5
5
  "keywords": [
6
6
  "Roblox",
@@ -27,22 +27,22 @@
27
27
  "access": "public"
28
28
  },
29
29
  "dependencies": {
30
- "@quenty/attributeutils": "^6.1.0",
31
- "@quenty/baseobject": "^5.0.0",
32
- "@quenty/binder": "^6.2.0",
33
- "@quenty/gameconfig": "^3.3.1",
30
+ "@quenty/attributeutils": "^6.2.0",
31
+ "@quenty/baseobject": "^5.1.0",
32
+ "@quenty/binder": "^6.3.0",
33
+ "@quenty/gameconfig": "^3.4.0",
34
34
  "@quenty/loader": "^5.0.0",
35
- "@quenty/maid": "^2.3.0",
36
- "@quenty/marketplaceutils": "^5.0.0",
37
- "@quenty/playerbinder": "^6.2.0",
38
- "@quenty/promise": "^5.0.0",
39
- "@quenty/remoting": "^5.1.0",
40
- "@quenty/rx": "^5.1.0",
41
- "@quenty/rxbinderutils": "^6.2.0",
42
- "@quenty/servicebag": "^5.0.0",
35
+ "@quenty/maid": "^2.4.0",
36
+ "@quenty/marketplaceutils": "^5.1.0",
37
+ "@quenty/playerbinder": "^6.3.0",
38
+ "@quenty/promise": "^5.1.0",
39
+ "@quenty/remoting": "^5.2.0",
40
+ "@quenty/rx": "^5.2.0",
41
+ "@quenty/rxbinderutils": "^6.3.0",
42
+ "@quenty/servicebag": "^5.1.0",
43
43
  "@quenty/signal": "^2.2.0",
44
- "@quenty/statestack": "^6.1.0",
44
+ "@quenty/statestack": "^6.2.0",
45
45
  "@quenty/table": "^3.1.0"
46
46
  },
47
- "gitHead": "67bd6a4f1957c3727c208d23c564c5757de6d7c8"
47
+ "gitHead": "e31b3a35aa475bb5699a24898a8639e107165b36"
48
48
  }
@@ -12,8 +12,6 @@ local GameProductServiceBase = require("GameProductServiceBase")
12
12
  local Signal = require("Signal")
13
13
  local GameConfigAssetTypes = require("GameConfigAssetTypes")
14
14
  local Promise = require("Promise")
15
- local RxStateStackUtils = require("RxStateStackUtils")
16
- local Rx = require("Rx")
17
15
 
18
16
  local GameProductServiceClient = GameProductServiceBase.new()
19
17
 
@@ -72,7 +70,7 @@ end
72
70
  function GameProductServiceClient:PromiseLocalPlayerOwnsPass(passIdOrKey)
73
71
  assert(type(passIdOrKey) == "number" or type(passIdOrKey) == "string", "Bad passIdOrKey")
74
72
 
75
- local passId = self:_toAssetId(GameConfigAssetTypes.PASS, passIdOrKey)
73
+ local passId = self:ToAssetId(GameConfigAssetTypes.PASS, passIdOrKey)
76
74
  if not passId then
77
75
  return Promise.rejected(("No asset with key %q"):format(tostring(passIdOrKey)))
78
76
  end
@@ -92,29 +90,6 @@ end
92
90
  function GameProductServiceBase:ObserveLocalPlayerOwnsPass(passIdOrKey)
93
91
  assert(type(passIdOrKey) == "number" or type(passIdOrKey) == "string", "Bad passIdOrKey")
94
92
 
95
- if type(passIdOrKey) == "string" then
96
- local picker = self._gameConfigService:GetConfigPicker()
97
- return picker:ObserveActiveAssetOfAssetIdBrio()
98
- :Pipe({
99
- RxStateStackUtils.topOfStack();
100
- Rx.switchMap(function(asset)
101
- if asset then
102
- return asset:ObserveAssetId()
103
- else
104
- return Rx.of(nil)
105
- end
106
- end);
107
- Rx.switchMap(function(assetId)
108
- if assetId then
109
- return self:ObservePlayerOwnsPass(Players.LocalPlayer, passIdOrKey)
110
- else
111
- warn(("No asset with key %q"):format(tostring(passIdOrKey)))
112
- return Rx.of(false)
113
- end
114
- end)
115
- })
116
- end
117
-
118
93
  return self:ObservePlayerOwnsPass(Players.LocalPlayer, passIdOrKey)
119
94
  end
120
95
 
@@ -141,7 +116,7 @@ function GameProductServiceClient:HasPurchasedProductThisSession(productIdOrKey)
141
116
  assert(self._serviceBag, "Not initialized")
142
117
  assert(type(productIdOrKey) == "number" or type(productIdOrKey) == "string", "productIdOrKey")
143
118
 
144
- local productId = self:_toAssetId(GameConfigAssetTypes.PRODUCT, productIdOrKey)
119
+ local productId = self:ToAssetId(GameConfigAssetTypes.PRODUCT, productIdOrKey)
145
120
  if not productId then
146
121
  warn(("No asset with key %q"):format(tostring(productIdOrKey)))
147
122
  return false
@@ -155,7 +130,7 @@ function GameProductServiceClient:HasPurchasedProductThisSession(productIdOrKey)
155
130
  end
156
131
 
157
132
  function GameProductServiceClient:PromisePurchasedOrPrompt(passIdOrKey)
158
- local gamepassId = self:_toAssetId(GameConfigAssetTypes.PASS, passIdOrKey)
133
+ local gamepassId = self:ToAssetId(GameConfigAssetTypes.PASS, passIdOrKey)
159
134
  if not gamepassId then
160
135
  return Promise.rejected(("No asset with key %q"):format(tostring(passIdOrKey)))
161
136
  end
@@ -174,12 +149,12 @@ function GameProductServiceClient:PromiseGamepassOrProductUnlockOrPrompt(passIdO
174
149
  assert(passIdOrKey, "Bad passIdOrKey")
175
150
  assert(productIdOrKey, "Bad productIdOrKey")
176
151
 
177
- local productId = self:_toAssetId(GameConfigAssetTypes.PRODUCT, productIdOrKey)
152
+ local productId = self:ToAssetId(GameConfigAssetTypes.PRODUCT, productIdOrKey)
178
153
  if not productId then
179
154
  return Promise.rejected(("No asset with key %q"):format(tostring(productIdOrKey)))
180
155
  end
181
156
 
182
- local gamepassId = self:_toAssetId(GameConfigAssetTypes.PASS, passIdOrKey)
157
+ local gamepassId = self:ToAssetId(GameConfigAssetTypes.PASS, passIdOrKey)
183
158
  if not gamepassId then
184
159
  return Promise.rejected(("No asset with key %q"):format(tostring(passIdOrKey)))
185
160
  end
@@ -199,21 +174,4 @@ function GameProductServiceClient:PromiseGamepassOrProductUnlockOrPrompt(passIdO
199
174
  end)
200
175
  end
201
176
 
202
-
203
- function GameProductServiceClient:_toAssetId(assetType, assetIdOrKey)
204
- assert(type(assetIdOrKey) == "number" or type(assetIdOrKey) == "string", "Bad assetIdOrKey")
205
-
206
- if type(assetIdOrKey) == "string" then
207
- local picker = self._gameConfigService:GetConfigPicker()
208
- local asset = picker:FindFirstActiveAssetOfKey(assetType, assetIdOrKey)
209
- if asset then
210
- return asset:GetAssetId()
211
- else
212
- return nil
213
- end
214
- end
215
-
216
- return assetIdOrKey
217
- end
218
-
219
177
  return GameProductServiceClient
@@ -11,6 +11,7 @@ local Players = game:GetService("Players")
11
11
  local PlayerProductManagerBase = require("PlayerProductManagerBase")
12
12
  local PlayerProductManagerConstants = require("PlayerProductManagerConstants")
13
13
  local GameConfigServiceClient = require("GameConfigServiceClient")
14
+ local Promise = require("Promise")
14
15
 
15
16
  local PlayerProductManagerClient = setmetatable({}, PlayerProductManagerBase)
16
17
  PlayerProductManagerClient.ClassName = "PlayerProductManagerClient"
@@ -24,15 +25,40 @@ function PlayerProductManagerClient.new(obj, serviceBag)
24
25
  self._serviceBag = assert(serviceBag, "No serviceBag")
25
26
  self._gameConfigServiceClient = self._serviceBag:GetService(GameConfigServiceClient)
26
27
 
28
+
27
29
  if self._obj == Players.LocalPlayer then
30
+ self._pendingPassPromises = {}
31
+
28
32
  self:PromiseRemoteEvent():Then(function(remoteEvent)
29
33
  self:_setupRemoteEventLocal(remoteEvent)
30
34
  end)
35
+
36
+ self._maid:GiveTask(MarketplaceService.PromptGamePassPurchaseFinished:Connect(function(player, gamePassId, isPurchased)
37
+ if player == self._obj then
38
+ self:_handlePassFinished(player, gamePassId, isPurchased)
39
+ end
40
+ end))
31
41
  end
32
42
 
33
43
  return self
34
44
  end
35
45
 
46
+ function PlayerProductManagerClient:PromptGamePassPurchase(gamePassId)
47
+ assert(type(gamePassId) == "number", "Bad gamePassId")
48
+ assert(self._obj == Players.LocalPlayer, "Can only prompt local player")
49
+
50
+ if self._pendingPassPromises[gamePassId] then
51
+ return self._maid:GivePromise(self._pendingPassPromises[gamePassId])
52
+ end
53
+
54
+ MarketplaceService:PromptGamePassPurchase(self._obj, gamePassId)
55
+ local promise = Promise.new()
56
+
57
+ self._pendingPassPromises[gamePassId] = promise
58
+
59
+ return self._maid:GivePromise(promise)
60
+ end
61
+
36
62
  function PlayerProductManagerClient:_setupRemoteEventLocal(remoteEvent)
37
63
  -- Gear and other assets
38
64
  self._maid:GiveTask(MarketplaceService.PromptPurchaseFinished:Connect(function(player, assetId, isPurchased)
@@ -61,4 +87,23 @@ function PlayerProductManagerClient:GetConfigPicker()
61
87
  return self._gameConfigServiceClient:GetConfigPicker()
62
88
  end
63
89
 
90
+ function PlayerProductManagerClient:_handlePassFinished(player, gamePassId, isPurchased)
91
+ assert(typeof(player) == "Instance", "Bad player")
92
+ assert(type(gamePassId) == "number", "Bad gamePassId")
93
+ assert(type(isPurchased) == "boolean", "Bad isPurchased")
94
+
95
+ local promise = self._pendingPassPromises[gamePassId]
96
+ if promise then
97
+ if isPurchased then
98
+ -- TODO: verify this on the server here
99
+ -- Can we break cache?
100
+ self:SetPlayerOwnsPass(gamePassId, true)
101
+ end
102
+
103
+ self._pendingPassPromises[gamePassId] = nil
104
+ promise:Resolve(isPurchased)
105
+ end
106
+ end
107
+
108
+
64
109
  return PlayerProductManagerClient
@@ -119,8 +119,8 @@ function PlayerProductManager:_handlePassFinished(player, gamePassId, isPurchase
119
119
  self:SetPlayerOwnsPass(gamePassId, true)
120
120
  end
121
121
 
122
- promise:Resolve(isPurchased)
123
122
  self._pendingPassPromises[gamePassId] = nil
123
+ promise:Resolve(isPurchased)
124
124
  end
125
125
  end
126
126
 
@@ -133,8 +133,8 @@ function PlayerProductManager:_handlePromptFinished(player, productId, isPurchas
133
133
  if promise then
134
134
  -- Success handled by receipt processing
135
135
  if not isPurchased then
136
- promise:Resolve(false)
137
136
  self._pendingProductPromises[productId] = nil
137
+ promise:Resolve(false)
138
138
  end
139
139
  end
140
140
  end
@@ -7,6 +7,9 @@ local require = require(script.Parent.loader).load(script)
7
7
  local promiseBoundClass = require("promiseBoundClass")
8
8
  local Rx = require("Rx")
9
9
  local RxBinderUtils = require("RxBinderUtils")
10
+ local GameConfigAssetTypes = require("GameConfigAssetTypes")
11
+ local Promise = require("Promise")
12
+ local RxStateStackUtils = require("RxStateStackUtils")
10
13
 
11
14
  local GameProductServiceBase = {}
12
15
  GameProductServiceBase.ClassName = "GameProductServiceBase"
@@ -22,14 +25,45 @@ function GameProductServiceBase:GetPlayerProductManagerBinder()
22
25
  error("Not implemented")
23
26
  end
24
27
 
25
- function GameProductServiceBase:ObservePlayerOwnsPass(player, gamePassId)
28
+ function GameProductServiceBase:ObservePlayerOwnsPass(player, passIdOrKey)
26
29
  assert(typeof(player) == "Instance", "Bad player")
27
- assert(type(gamePassId) == "number", "Bad gamePassId")
30
+
31
+ if type(passIdOrKey) == "string" then
32
+ local picker = self._gameConfigService:GetConfigPicker()
33
+ return picker:ObserveActiveAssetOfAssetTypeAndKeyBrio(GameConfigAssetTypes.PASS, passIdOrKey)
34
+ :Pipe({
35
+ RxStateStackUtils.topOfStack();
36
+ Rx.switchMap(function(asset)
37
+ if asset then
38
+ return asset:ObserveAssetId()
39
+ else
40
+ return Rx.of(nil)
41
+ end
42
+ end);
43
+ Rx.switchMap(function(assetId)
44
+ if assetId then
45
+ return self:_observePlayerOwnsPassForId(player, assetId)
46
+ else
47
+ warn(("No pass with key %q"):format(tostring(passIdOrKey)))
48
+ return Rx.of(false)
49
+ end
50
+ end)
51
+ })
52
+ elseif type(passIdOrKey) == "number" then
53
+ return self:_observePlayerOwnsPassForId(player, passIdOrKey)
54
+ else
55
+ error("[GameProductServiceBase.ObservePlayerOwnsPass] - Bad passIdOrKey")
56
+ end
57
+ end
58
+
59
+ function GameProductServiceBase:_observePlayerOwnsPassForId(player, passId)
60
+ assert(typeof(player) == "Instance", "Bad player")
61
+ assert(type(passId) == "number", "Bad passId")
28
62
 
29
63
  return self:_observeManager(player):Pipe({
30
64
  Rx.switchMap(function(manager)
31
65
  if manager then
32
- return manager:ObservePlayerOwnsPass(gamePassId)
66
+ return manager:ObservePlayerOwnsPass(passId)
33
67
  else
34
68
  return Rx.of(false)
35
69
  end
@@ -37,29 +71,44 @@ function GameProductServiceBase:ObservePlayerOwnsPass(player, gamePassId)
37
71
  })
38
72
  end
39
73
 
40
- function GameProductServiceBase:PromisePlayerOwnsPass(player, gamePassId)
74
+ function GameProductServiceBase:PromisePlayerOwnsPass(player, passIdOrKey)
41
75
  assert(typeof(player) == "Instance", "Bad player")
42
- assert(type(gamePassId) == "number", "Bad gamePassId")
76
+ assert(type(passIdOrKey) == "number" or type(passIdOrKey) == "string", "Bad passIdOrKey")
77
+
78
+ local passId = self:ToAssetId(GameConfigAssetTypes.PASS, passIdOrKey)
79
+ if not passId then
80
+ return Promise.rejected(("No pass with key %q"):format(tostring(passIdOrKey)))
81
+ end
43
82
 
44
83
  return self:_promiseManager(player)
45
84
  :Then(function(manager)
46
- return manager:PromisePlayerOwnsPass(gamePassId)
85
+ return manager:PromisePlayerOwnsPass(passId)
47
86
  end)
48
87
  end
49
88
 
50
- function GameProductServiceBase:PromptGamePassPurchase(player, gamePassId)
89
+ function GameProductServiceBase:PromptGamePassPurchase(player, passIdOrKey)
51
90
  assert(typeof(player) == "Instance", "Bad player")
52
- assert(type(gamePassId) == "number", "Bad gamePassId")
91
+ assert(type(passIdOrKey) == "number" or type(passIdOrKey) == "string", "Bad passIdOrKey")
92
+
93
+ local passId = self:ToAssetId(GameConfigAssetTypes.PASS, passIdOrKey)
94
+ if not passId then
95
+ return Promise.rejected(("No pass with key %q"):format(tostring(passIdOrKey)))
96
+ end
53
97
 
54
98
  return self:_promiseManager(player)
55
99
  :Then(function(manager)
56
- return manager:PromptGamePassPurchase(gamePassId)
100
+ return manager:PromptGamePassPurchase(passId)
57
101
  end)
58
102
  end
59
103
 
60
- function GameProductServiceBase:PromisePromptPurchase(player, productId)
104
+ function GameProductServiceBase:PromisePromptPurchase(player, productIdOrKey)
61
105
  assert(typeof(player) == "Instance", "Bad player")
62
- assert(type(productId) == "number", "Bad productId")
106
+ assert(type(productIdOrKey) == "number", "Bad productIdOrKey")
107
+
108
+ local productId = self:ToAssetId(GameConfigAssetTypes.PRODUCT, productIdOrKey)
109
+ if not productId then
110
+ return Promise.rejected(("No product with key %q"):format(tostring(productIdOrKey)))
111
+ end
63
112
 
64
113
  return self:_promiseManager(player)
65
114
  :Then(function(manager)
@@ -67,6 +116,21 @@ function GameProductServiceBase:PromisePromptPurchase(player, productId)
67
116
  end)
68
117
  end
69
118
 
119
+ function GameProductServiceBase:ToAssetId(assetType, assetIdOrKey)
120
+ assert(type(assetIdOrKey) == "number" or type(assetIdOrKey) == "string", "Bad assetIdOrKey")
121
+
122
+ if type(assetIdOrKey) == "string" then
123
+ local picker = self._gameConfigService:GetConfigPicker()
124
+ local asset = picker:FindFirstActiveAssetOfKey(assetType, assetIdOrKey)
125
+ if asset then
126
+ return asset:GetAssetId()
127
+ else
128
+ return nil
129
+ end
130
+ end
131
+
132
+ return assetIdOrKey
133
+ end
70
134
 
71
135
  function GameProductServiceBase:_observeManager(player)
72
136
  assert(typeof(player) == "Instance", "Bad player")
@@ -81,4 +145,5 @@ function GameProductServiceBase:_promiseManager(player)
81
145
  end
82
146
 
83
147
 
148
+
84
149
  return GameProductServiceBase
@@ -2,8 +2,6 @@
2
2
  @class PlayerProductManagerUtils
3
3
  ]=]
4
4
 
5
- local require = require(script.Parent.loader).load(script)
6
-
7
5
  local PlayerProductManagerUtils = {}
8
6
 
9
7
  function PlayerProductManagerUtils.toOwnedAttribute(assetKey)