@quenty/settings 11.61.0 → 11.62.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,12 @@
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
+ # [11.62.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/settings@11.61.0...@quenty/settings@11.62.0) (2026-07-23)
7
+
8
+ ### Features
9
+
10
+ - Add baseline player-mock and support across Nevermore for mocked players. ([567d121](https://github.com/Quenty/NevermoreEngine/commit/567d121ffc014b42391554088189a1a6296dda83))
11
+
6
12
  # [11.61.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/settings@11.60.0...@quenty/settings@11.61.0) (2026-07-22)
7
13
 
8
14
  **Note:** Version bump only for package @quenty/settings
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/settings",
3
- "version": "11.61.0",
3
+ "version": "11.62.0",
4
4
  "description": "Centralized player settings service",
5
5
  "keywords": [
6
6
  "Roblox",
@@ -28,42 +28,43 @@
28
28
  "Quenty"
29
29
  ],
30
30
  "dependencies": {
31
- "@quenty/attributeutils": "14.32.0",
32
- "@quenty/baseobject": "10.14.0",
33
- "@quenty/binder": "14.40.0",
34
- "@quenty/brio": "14.32.0",
35
- "@quenty/canceltoken": "11.21.0",
36
- "@quenty/cmdrservice": "13.50.0",
37
- "@quenty/datastore": "13.45.0",
31
+ "@quenty/attributeutils": "14.33.0",
32
+ "@quenty/baseobject": "10.15.0",
33
+ "@quenty/binder": "14.41.0",
34
+ "@quenty/brio": "14.33.0",
35
+ "@quenty/canceltoken": "11.22.0",
36
+ "@quenty/cmdrservice": "13.51.0",
37
+ "@quenty/datastore": "13.46.0",
38
38
  "@quenty/ducktype": "5.11.0",
39
39
  "@quenty/enumutils": "3.4.6",
40
- "@quenty/instanceutils": "13.32.0",
41
- "@quenty/jsonutils": "10.20.0",
40
+ "@quenty/instanceutils": "13.33.0",
41
+ "@quenty/jsonutils": "10.21.0",
42
42
  "@quenty/loader": "10.11.0",
43
- "@quenty/maid": "3.10.0",
44
- "@quenty/nevermore-test-runner": "1.4.0",
45
- "@quenty/observablecollection": "12.41.0",
46
- "@quenty/playerbinder": "14.40.0",
47
- "@quenty/playerutils": "8.35.0",
48
- "@quenty/promise": "10.20.0",
49
- "@quenty/remotefunctionutils": "10.20.0",
50
- "@quenty/remoting": "12.35.0",
51
- "@quenty/rx": "13.30.0",
52
- "@quenty/rxbinderutils": "14.40.0",
53
- "@quenty/rxsignal": "7.30.0",
54
- "@quenty/servicebag": "11.19.0",
43
+ "@quenty/maid": "3.11.0",
44
+ "@quenty/nevermore-test-runner": "1.5.0",
45
+ "@quenty/observablecollection": "12.42.0",
46
+ "@quenty/playerbinder": "14.41.0",
47
+ "@quenty/playermock": "1.1.0",
48
+ "@quenty/playerutils": "8.36.0",
49
+ "@quenty/promise": "10.21.0",
50
+ "@quenty/remotefunctionutils": "10.21.0",
51
+ "@quenty/remoting": "12.36.0",
52
+ "@quenty/rx": "13.31.0",
53
+ "@quenty/rxbinderutils": "14.41.0",
54
+ "@quenty/rxsignal": "7.31.0",
55
+ "@quenty/servicebag": "11.20.0",
55
56
  "@quenty/signal": "7.13.1",
56
- "@quenty/statestack": "14.34.0",
57
- "@quenty/string": "3.3.7",
57
+ "@quenty/statestack": "14.35.0",
58
+ "@quenty/string": "3.4.0",
58
59
  "@quenty/symbol": "3.5.2",
59
60
  "@quenty/table": "3.9.2",
60
- "@quenty/throttle": "10.13.0",
61
- "@quenty/tie": "10.43.0",
62
- "@quenty/valueobject": "13.33.0",
61
+ "@quenty/throttle": "10.14.0",
62
+ "@quenty/tie": "10.44.0",
63
+ "@quenty/valueobject": "13.34.0",
63
64
  "@quentystudios/jest-lua": "3.10.0-quenty.2"
64
65
  },
65
66
  "publishConfig": {
66
67
  "access": "public"
67
68
  },
68
- "gitHead": "93f15b200c0f465a0b5304fcf05f5cfe7fdcbd1d"
69
+ "gitHead": "1de37218a2bedb8e3f8614a2e09bba9eddc812da"
69
70
  }
@@ -15,6 +15,7 @@ local Brio = require("Brio")
15
15
  local CancelToken = require("CancelToken")
16
16
  local Maid = require("Maid")
17
17
  local Observable = require("Observable")
18
+ local PlayerMock = require("PlayerMock")
18
19
  local PlayerSettingsClient = require("PlayerSettingsClient")
19
20
  local Promise = require("Promise")
20
21
  local ServiceBag = require("ServiceBag")
@@ -62,7 +63,7 @@ end
62
63
  function SettingsServiceClient.GetLocalPlayerSettings(
63
64
  self: SettingsServiceClient
64
65
  ): PlayerSettingsClient.PlayerSettingsClient?
65
- return self:GetPlayerSettings(Players.LocalPlayer)
66
+ return self:GetPlayerSettings(Players.LocalPlayer or PlayerMock.getMockedLocalPlayer())
66
67
  end
67
68
 
68
69
  --[=[
@@ -73,7 +74,7 @@ end
73
74
  function SettingsServiceClient.ObserveLocalPlayerSettingsBrio(self: SettingsServiceClient): Observable.Observable<
74
75
  Brio.Brio<PlayerSettingsClient.PlayerSettingsClient>
75
76
  >
76
- return self:ObservePlayerSettingsBrio(Players.LocalPlayer)
77
+ return self:ObservePlayerSettingsBrio(Players.LocalPlayer or PlayerMock.getMockedLocalPlayer())
77
78
  end
78
79
 
79
80
  --[=[
@@ -84,7 +85,7 @@ end
84
85
  function SettingsServiceClient.ObserveLocalPlayerSettings(self: SettingsServiceClient): Observable.Observable<
85
86
  PlayerSettingsClient.PlayerSettingsClient
86
87
  >
87
- return self:ObservePlayerSettings(Players.LocalPlayer)
88
+ return self:ObservePlayerSettings(Players.LocalPlayer or PlayerMock.getMockedLocalPlayer())
88
89
  end
89
90
 
90
91
  --[=[
@@ -97,7 +98,7 @@ function SettingsServiceClient.PromiseLocalPlayerSettings(
97
98
  self: SettingsServiceClient,
98
99
  cancelToken: CancelToken.CancelToken
99
100
  ): Promise.Promise<PlayerSettingsClient.PlayerSettingsClient>
100
- return self:PromisePlayerSettings(Players.LocalPlayer, cancelToken)
101
+ return self:PromisePlayerSettings(Players.LocalPlayer or PlayerMock.getMockedLocalPlayer(), cancelToken)
101
102
  end
102
103
 
103
104
  --[=[
@@ -110,7 +111,7 @@ function SettingsServiceClient.ObservePlayerSettings(
110
111
  self: SettingsServiceClient,
111
112
  player: Player
112
113
  ): Observable.Observable<PlayerSettingsClient.PlayerSettingsClient>
113
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
114
+ assert(typeof(player) == "Instance" and (player:IsA("Player") or PlayerMock.isMock(player)), "Bad player")
114
115
 
115
116
  return self._settingsDataService:ObservePlayerSettings(player)
116
117
  end
@@ -127,7 +128,7 @@ function SettingsServiceClient.ObservePlayerSettingsBrio(
127
128
  ): Observable.Observable<
128
129
  Brio.Brio<PlayerSettingsClient.PlayerSettingsClient>
129
130
  >
130
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
131
+ assert(typeof(player) == "Instance" and (player:IsA("Player") or PlayerMock.isMock(player)), "Bad player")
131
132
 
132
133
  return self._settingsDataService:ObservePlayerSettingsBrio(player)
133
134
  end
@@ -142,7 +143,7 @@ function SettingsServiceClient.GetPlayerSettings(
142
143
  self: SettingsServiceClient,
143
144
  player: Player
144
145
  ): PlayerSettingsClient.PlayerSettingsClient?
145
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
146
+ assert(typeof(player) == "Instance" and (player:IsA("Player") or PlayerMock.isMock(player)), "Bad player")
146
147
 
147
148
  return self._settingsDataService:GetPlayerSettings(player)
148
149
  end
@@ -159,7 +160,7 @@ function SettingsServiceClient.PromisePlayerSettings(
159
160
  player: Player,
160
161
  cancelToken: CancelToken.CancelToken
161
162
  ): Promise.Promise<PlayerSettingsClient.PlayerSettingsClient>
162
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
163
+ assert(typeof(player) == "Instance" and (player:IsA("Player") or PlayerMock.isMock(player)), "Bad player")
163
164
 
164
165
  return self._settingsDataService:PromisePlayerSettings(player, cancelToken)
165
166
  end
@@ -10,6 +10,7 @@ local require = require(script.Parent.loader).load(script)
10
10
  local BaseObject = require("BaseObject")
11
11
  local DataStoreStringUtils = require("DataStoreStringUtils")
12
12
  local Observable = require("Observable")
13
+ local PlayerMock = require("PlayerMock")
13
14
  local PlayerSettingsUtils = require("PlayerSettingsUtils")
14
15
  local Rx = require("Rx")
15
16
  local RxAttributeUtils = require("RxAttributeUtils")
@@ -51,7 +52,9 @@ end
51
52
  @return Player
52
53
  ]=]
53
54
  function PlayerSettingsBase.GetPlayer(self: PlayerSettingsBase): Player?
54
- return self._obj:FindFirstAncestorWhichIsA("Player")
55
+ -- The real Player ancestor, or the PlayerMock a test parented the settings folder under
56
+ -- (a mock's backing Folder is invisible to the IsA walk).
57
+ return self._obj:FindFirstAncestorWhichIsA("Player") or PlayerMock.findFirstAncestorMock(self._obj)
55
58
  end
56
59
 
57
60
  --[=[
@@ -26,6 +26,7 @@ local Players = game:GetService("Players")
26
26
  local DuckTypeUtils = require("DuckTypeUtils")
27
27
  local Maid = require("Maid")
28
28
  local Observable = require("Observable")
29
+ local PlayerMock = require("PlayerMock")
29
30
  local Promise = require("Promise")
30
31
  local ServiceBag = require("ServiceBag")
31
32
  local SettingProperty = require("SettingProperty")
@@ -175,9 +176,13 @@ function SettingDefinition.GetSettingProperty<T>(
175
176
  player: Player
176
177
  ): SettingProperty.SettingProperty<T>
177
178
  assert(ServiceBag.isServiceBag(serviceBag), "Bad serviceBag")
178
- assert(typeof(player) == "Instance" and player:IsA("Player") or player == nil, "Bad player")
179
+ assert(
180
+ typeof(player) == "Instance" and (player:IsA("Player") or PlayerMock.isMock(player)) or player == nil,
181
+ "Bad player"
182
+ )
179
183
 
180
- player = player or Players.LocalPlayer
184
+ -- May still be nil in a non-running DataModel; SettingProperty resolves the local player lazily.
185
+ player = player or Players.LocalPlayer or PlayerMock.getMockedLocalPlayer()
181
186
 
182
187
  return SettingProperty.new(serviceBag, player, self)
183
188
  end
@@ -194,7 +199,7 @@ function SettingDefinition.GetLocalPlayerSettingProperty<T>(
194
199
  ): SettingProperty.SettingProperty<T>
195
200
  assert(ServiceBag.isServiceBag(serviceBag), "Bad serviceBag")
196
201
 
197
- return self:GetSettingProperty(serviceBag, Players.LocalPlayer)
202
+ return self:GetSettingProperty(serviceBag, Players.LocalPlayer or PlayerMock.getMockedLocalPlayer())
198
203
  end
199
204
 
200
205
  --[=[
@@ -5,7 +5,10 @@
5
5
 
6
6
  local require = require(script.Parent.loader).load(script)
7
7
 
8
+ local Players = game:GetService("Players")
9
+
8
10
  local Observable = require("Observable")
11
+ local PlayerMock = require("PlayerMock")
9
12
  local Promise = require("Promise")
10
13
  local Rx = require("Rx")
11
14
  local RxSignal = require("RxSignal")
@@ -24,7 +27,7 @@ export type SettingProperty<T> = typeof(setmetatable(
24
27
 
25
28
  _serviceBag: ServiceBag.ServiceBag,
26
29
  _bridge: SettingsDataService.SettingsDataService,
27
- _player: Player,
30
+ _player: Player?,
28
31
  _definition: any,
29
32
  },
30
33
  {} :: typeof({ __index = SettingProperty })
@@ -33,23 +36,33 @@ export type SettingProperty<T> = typeof(setmetatable(
33
36
  --[=[
34
37
  Constructs a new SettingProperty.
35
38
 
39
+ A nil player means the local player: the real `Players.LocalPlayer`, or the mock a test has
40
+ already designated through [PlayerMock.setMockedLocalPlayer]. Designation may happen before
41
+ bags boot -- matching production, where `Players.LocalPlayer` exists before any service runs --
42
+ so construction requires a resolvable local player up front.
43
+
36
44
  @param serviceBag ServiceBag
37
- @param player Player
45
+ @param player Player?
38
46
  @param definition SettingDefinition
39
47
  @return SettingProperty<T>
40
48
  ]=]
41
- function SettingProperty.new<T>(serviceBag: ServiceBag.ServiceBag, player: Player, definition): SettingProperty<T>
49
+ function SettingProperty.new<T>(serviceBag: ServiceBag.ServiceBag, player: Player?, definition): SettingProperty<T>
42
50
  local self: SettingProperty<T> = setmetatable({} :: any, SettingProperty)
43
51
 
44
52
  self._serviceBag = assert(serviceBag, "No serviceBag")
45
53
  self._bridge = self._serviceBag:GetService(SettingsDataService) :: any
46
54
 
47
- self._player = assert(player, "No player")
55
+ assert(player ~= nil or Players.LocalPlayer ~= nil or PlayerMock.getMockedLocalPlayer() ~= nil, "No player")
56
+ if player ~= nil then
57
+ self._player = player
58
+ end
48
59
  self._definition = assert(definition, "No definition")
49
60
 
50
- self:_promisePlayerSettings():Then(function(playerSettings)
51
- playerSettings:EnsureInitialized(self._definition:GetSettingName(), self._definition:GetDefaultValue())
52
- end)
61
+ if self:_findPlayer() ~= nil then
62
+ self:_promisePlayerSettings():Then(function(playerSettings)
63
+ playerSettings:EnsureInitialized(self._definition:GetSettingName(), self._definition:GetDefaultValue())
64
+ end)
65
+ end
53
66
 
54
67
  return self
55
68
  end
@@ -191,16 +204,24 @@ function SettingProperty.PromiseRestoreDefault<T>(self: SettingProperty<T>): Pro
191
204
  end)
192
205
  end
193
206
 
207
+ function SettingProperty._findPlayer<T>(self: SettingProperty<T>): Player?
208
+ return rawget(self :: any, "_player") or Players.LocalPlayer or PlayerMock.getMockedLocalPlayer()
209
+ end
210
+
211
+ function SettingProperty._resolvePlayer<T>(self: SettingProperty<T>): Player
212
+ return assert(self:_findPlayer(), "No player") :: Player
213
+ end
214
+
194
215
  function SettingProperty._observePlayerSettings<T>(self: SettingProperty<T>)
195
- return self._bridge:ObservePlayerSettings(self._player)
216
+ return self._bridge:ObservePlayerSettings(self:_resolvePlayer())
196
217
  end
197
218
 
198
219
  function SettingProperty._getPlayerSettings<T>(self: SettingProperty<T>)
199
- return self._bridge:GetPlayerSettings(self._player)
220
+ return self._bridge:GetPlayerSettings(self:_resolvePlayer())
200
221
  end
201
222
 
202
223
  function SettingProperty._promisePlayerSettings<T>(self: SettingProperty<T>)
203
- return self._bridge:PromisePlayerSettings(self._player)
224
+ return self._bridge:PromisePlayerSettings(self:_resolvePlayer())
204
225
  end
205
226
 
206
227
  return SettingProperty
@@ -14,6 +14,7 @@ local Maid = require("Maid")
14
14
  local Observable = require("Observable")
15
15
  local ObservableMap = require("ObservableMap")
16
16
  local ObservableSet = require("ObservableSet")
17
+ local PlayerMock = require("PlayerMock")
17
18
  local PlayerSettingsInterface = require("PlayerSettingsInterface")
18
19
  local Promise = require("Promise")
19
20
  local Rx = require("Rx")
@@ -154,7 +155,7 @@ function SettingsDataService.ObservePlayerSettings(
154
155
  self: SettingsDataService,
155
156
  player: Player
156
157
  ): Observable.Observable<any>
157
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
158
+ assert(typeof(player) == "Instance" and (player:IsA("Player") or PlayerMock.isMock(player)), "Bad player")
158
159
 
159
160
  return (self:_getPlayerSettingsMapForPlayer(player) :: any):ObserveAtKey(
160
161
  player,
@@ -190,7 +191,7 @@ function SettingsDataService.PromisePlayerSettings(
190
191
  player: Player,
191
192
  cancelToken: any
192
193
  ): Promise.Promise<any>
193
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
194
+ assert(typeof(player) == "Instance" and (player:IsA("Player") or PlayerMock.isMock(player)), "Bad player")
194
195
 
195
196
  return Rx.toPromise(
196
197
  (self:ObservePlayerSettings(player) :: any):Pipe({
@@ -209,7 +210,7 @@ end
209
210
  @return Promise<PlayerSettingsBase>
210
211
  ]=]
211
212
  function SettingsDataService.GetPlayerSettings(self: SettingsDataService, player: Player): any
212
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
213
+ assert(typeof(player) == "Instance" and (player:IsA("Player") or PlayerMock.isMock(player)), "Bad player")
213
214
 
214
215
  return self:_getPlayerSettingsMapForPlayer(player):Get(player)
215
216
  end