@quenty/settings 4.12.0 → 4.13.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 +11 -0
- package/package.json +4 -4
- package/src/Client/Player/PlayerSettingsClient.lua +47 -6
- package/src/Client/SettingsServiceClient.lua +54 -0
- package/src/Server/Player/PlayerHasSettings.lua +16 -0
- package/src/Server/Player/PlayerSettings.lua +46 -2
- package/src/Shared/Player/PlayerSettingsBase.lua +25 -2
- package/src/Shared/Player/PlayerSettingsConstants.lua +1 -0
- package/src/Shared/Player/PlayerSettingsUtils.lua +75 -3
- package/src/Shared/Setting/SettingDefinition.lua +16 -0
- package/src/Shared/Setting/SettingDefinitionProvider.lua +86 -1
- package/src/Shared/Setting/SettingProperty.lua +52 -4
- package/src/Shared/SettingRegistryServiceShared.lua +61 -0
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
|
+
# [4.13.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/settings@4.12.0...@quenty/settings@4.13.0) (2023-01-17)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Ensure that Settings can't contain invalid UTF8 characters and document settings package better ([cbf1406](https://github.com/Quenty/NevermoreEngine/commit/cbf140620795846daf35ce6945bcdf801e1156f9))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
# [4.12.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/settings@4.11.1...@quenty/settings@4.12.0) (2023-01-11)
|
|
7
18
|
|
|
8
19
|
**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": "4.
|
|
3
|
+
"version": "4.13.0",
|
|
4
4
|
"description": "Centralized player settings service",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"Quenty"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@quenty/attributeutils": "^8.
|
|
28
|
+
"@quenty/attributeutils": "^8.5.0",
|
|
29
29
|
"@quenty/baseobject": "^6.0.1",
|
|
30
30
|
"@quenty/binder": "^8.6.0",
|
|
31
|
-
"@quenty/datastore": "^7.
|
|
31
|
+
"@quenty/datastore": "^7.5.0",
|
|
32
32
|
"@quenty/enumutils": "^3.0.0",
|
|
33
33
|
"@quenty/jsonutils": "^6.0.1",
|
|
34
34
|
"@quenty/loader": "^6.0.1",
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"publishConfig": {
|
|
52
52
|
"access": "public"
|
|
53
53
|
},
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "a89a3f27cad25767cd645b91cdc2a2881afeecd5"
|
|
55
55
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
--[=[
|
|
2
|
+
A player's current settings. Handles replication back to the server
|
|
3
|
+
when a setting changes. See [PlayerSettingsBase].
|
|
4
|
+
|
|
5
|
+
@client
|
|
2
6
|
@class PlayerSettingsClient
|
|
3
7
|
]=]
|
|
4
8
|
|
|
@@ -6,14 +10,15 @@ local require = require(script.Parent.loader).load(script)
|
|
|
6
10
|
|
|
7
11
|
local Players = game:GetService("Players")
|
|
8
12
|
|
|
13
|
+
local DataStoreStringUtils = require("DataStoreStringUtils")
|
|
14
|
+
local Maid = require("Maid")
|
|
15
|
+
local Observable = require("Observable")
|
|
9
16
|
local PlayerSettingsBase = require("PlayerSettingsBase")
|
|
10
17
|
local PlayerSettingsConstants = require("PlayerSettingsConstants")
|
|
11
|
-
local RemoteFunctionUtils = require("RemoteFunctionUtils")
|
|
12
18
|
local PlayerSettingsUtils = require("PlayerSettingsUtils")
|
|
13
|
-
local
|
|
14
|
-
local Maid = require("Maid")
|
|
19
|
+
local RemoteFunctionUtils = require("RemoteFunctionUtils")
|
|
15
20
|
local Symbol = require("Symbol")
|
|
16
|
-
local
|
|
21
|
+
local ThrottledFunction = require("ThrottledFunction")
|
|
17
22
|
local ValueObject = require("ValueObject")
|
|
18
23
|
|
|
19
24
|
local UNSET_VALUE = Symbol.named("unsetValue")
|
|
@@ -24,8 +29,15 @@ PlayerSettingsClient.__index = PlayerSettingsClient
|
|
|
24
29
|
|
|
25
30
|
require("PromiseRemoteFunctionMixin"):Add(PlayerSettingsClient, PlayerSettingsConstants.REMOTE_FUNCTION_NAME)
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
--[=[
|
|
33
|
+
See [SettingsBindersClient] and [SettingsServiceClient] on how to properly use this class.
|
|
34
|
+
|
|
35
|
+
@param folder Folder
|
|
36
|
+
@param serviceBag ServiceBag
|
|
37
|
+
@return PlayerSettingsClient
|
|
38
|
+
]=]
|
|
39
|
+
function PlayerSettingsClient.new(folder, serviceBag)
|
|
40
|
+
local self = setmetatable(PlayerSettingsBase.new(folder, serviceBag), PlayerSettingsClient)
|
|
29
41
|
|
|
30
42
|
if self:GetPlayer() == Players.LocalPlayer then
|
|
31
43
|
self._toReplicate = nil
|
|
@@ -48,6 +60,13 @@ function PlayerSettingsClient.new(obj, serviceBag)
|
|
|
48
60
|
return self
|
|
49
61
|
end
|
|
50
62
|
|
|
63
|
+
--[=[
|
|
64
|
+
Gets a settings value
|
|
65
|
+
|
|
66
|
+
@param settingName string
|
|
67
|
+
@param defaultValue T
|
|
68
|
+
@return T
|
|
69
|
+
]=]
|
|
51
70
|
function PlayerSettingsClient:GetValue(settingName, defaultValue)
|
|
52
71
|
assert(type(settingName) == "string", "Bad settingName")
|
|
53
72
|
|
|
@@ -63,6 +82,13 @@ function PlayerSettingsClient:GetValue(settingName, defaultValue)
|
|
|
63
82
|
return getmetatable(PlayerSettingsClient).GetValue(self, settingName, defaultValue)
|
|
64
83
|
end
|
|
65
84
|
|
|
85
|
+
--[=[
|
|
86
|
+
Observes a settings value.
|
|
87
|
+
|
|
88
|
+
@param settingName string
|
|
89
|
+
@param defaultValue T
|
|
90
|
+
@return Observable<T>
|
|
91
|
+
]=]
|
|
66
92
|
function PlayerSettingsClient:ObserveValue(settingName, defaultValue)
|
|
67
93
|
assert(type(settingName) == "string", "Bad settingName")
|
|
68
94
|
|
|
@@ -128,9 +154,24 @@ function PlayerSettingsClient:ObserveValue(settingName, defaultValue)
|
|
|
128
154
|
end)
|
|
129
155
|
end
|
|
130
156
|
|
|
157
|
+
--[=[
|
|
158
|
+
Sets a settings value and replicates the value eventually (in a de-duplicated manner).
|
|
159
|
+
|
|
160
|
+
@param settingName string
|
|
161
|
+
@param value T
|
|
162
|
+
]=]
|
|
131
163
|
function PlayerSettingsClient:SetValue(settingName, value)
|
|
132
164
|
assert(type(settingName) == "string", "Bad settingName")
|
|
133
165
|
assert(self:GetPlayer() == Players.LocalPlayer, "Cannot set settings of another player")
|
|
166
|
+
assert(DataStoreStringUtils.isValidUTF8(settingName), "Bad settingName")
|
|
167
|
+
|
|
168
|
+
if type(value) == "string" then
|
|
169
|
+
assert(DataStoreStringUtils.isValidUTF8(value), "Invalid string")
|
|
170
|
+
|
|
171
|
+
if (#value + #settingName) > PlayerSettingsConstants.MAX_SETTINGS_LENGTH then
|
|
172
|
+
error(string.format("[PlayerSettingsClient.SetValue] - Setting is too long for %q", settingName))
|
|
173
|
+
end
|
|
174
|
+
end
|
|
134
175
|
|
|
135
176
|
local queueReplication = false
|
|
136
177
|
if not self._toReplicate then
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
--[=[
|
|
2
|
+
Provides access to settings on the client. See [SettingDefinition] which should
|
|
3
|
+
register settings on the server. See [SettingsService] for server component.
|
|
4
|
+
|
|
5
|
+
@client
|
|
2
6
|
@class SettingsServiceClient
|
|
3
7
|
]=]
|
|
4
8
|
|
|
@@ -11,6 +15,11 @@ local Rx = require("Rx")
|
|
|
11
15
|
|
|
12
16
|
local SettingsServiceClient = {}
|
|
13
17
|
|
|
18
|
+
--[=[
|
|
19
|
+
Initializes the setting service. Should be done via ServiceBag.
|
|
20
|
+
|
|
21
|
+
@param serviceBag ServiceBag
|
|
22
|
+
]=]
|
|
14
23
|
function SettingsServiceClient:Init(serviceBag)
|
|
15
24
|
assert(not self._serviceBag, "Already initialized")
|
|
16
25
|
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
@@ -20,40 +29,85 @@ function SettingsServiceClient:Init(serviceBag)
|
|
|
20
29
|
self._binders = self._serviceBag:GetService(require("SettingsBindersClient"))
|
|
21
30
|
end
|
|
22
31
|
|
|
32
|
+
--[=[
|
|
33
|
+
Gets the local player settings
|
|
34
|
+
@return PlayerSettingsClient | nil
|
|
35
|
+
]=]
|
|
23
36
|
function SettingsServiceClient:GetLocalPlayerSettings()
|
|
24
37
|
return self:GetPlayerSettings(Players.LocalPlayer)
|
|
25
38
|
end
|
|
26
39
|
|
|
40
|
+
--[=[
|
|
41
|
+
Observes the local player settings in a brio
|
|
42
|
+
|
|
43
|
+
@return Observable<Brio<PlayerSettingsClient>>
|
|
44
|
+
]=]
|
|
27
45
|
function SettingsServiceClient:ObserveLocalPlayerSettingsBrio()
|
|
28
46
|
return self:ObservePlayerSettingsBrio(Players.LocalPlayer)
|
|
29
47
|
end
|
|
30
48
|
|
|
49
|
+
--[=[
|
|
50
|
+
Observes the local player settings
|
|
51
|
+
|
|
52
|
+
@return Observable<PlayerSettingsClient | nil>
|
|
53
|
+
]=]
|
|
31
54
|
function SettingsServiceClient:ObserveLocalPlayerSettings()
|
|
32
55
|
return self:ObservePlayerSettings(Players.LocalPlayer)
|
|
33
56
|
end
|
|
34
57
|
|
|
58
|
+
--[=[
|
|
59
|
+
Promises the local player settings
|
|
60
|
+
|
|
61
|
+
@param cancelToken CancellationToken
|
|
62
|
+
@return Promise<PlayerSettingsClient>
|
|
63
|
+
]=]
|
|
35
64
|
function SettingsServiceClient:PromiseLocalPlayerSettings(cancelToken)
|
|
36
65
|
return self:PromisePlayerSettings(Players.LocalPlayer, cancelToken)
|
|
37
66
|
end
|
|
38
67
|
|
|
68
|
+
--[=[
|
|
69
|
+
Observes the player settings
|
|
70
|
+
|
|
71
|
+
@param player Player
|
|
72
|
+
@return Observable<PlayerSettingsClient | nil>
|
|
73
|
+
]=]
|
|
39
74
|
function SettingsServiceClient:ObservePlayerSettings(player)
|
|
40
75
|
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
41
76
|
|
|
42
77
|
return PlayerSettingsUtils.observePlayerSettings(self._binders.PlayerSettings, player)
|
|
43
78
|
end
|
|
44
79
|
|
|
80
|
+
--[=[
|
|
81
|
+
Observes the player settings in a brio
|
|
82
|
+
|
|
83
|
+
@param player Player
|
|
84
|
+
@return Observable<Brio<PlayerSettingsClient>>
|
|
85
|
+
]=]
|
|
45
86
|
function SettingsServiceClient:ObservePlayerSettingsBrio(player)
|
|
46
87
|
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
47
88
|
|
|
48
89
|
return PlayerSettingsUtils.observePlayerSettingsBrio(self._binders.PlayerSettings, player)
|
|
49
90
|
end
|
|
50
91
|
|
|
92
|
+
--[=[
|
|
93
|
+
Gets a player's settings
|
|
94
|
+
|
|
95
|
+
@param player Player
|
|
96
|
+
@return PlayerSettingsClient | nil
|
|
97
|
+
]=]
|
|
51
98
|
function SettingsServiceClient:GetPlayerSettings(player)
|
|
52
99
|
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
53
100
|
|
|
54
101
|
return PlayerSettingsUtils.getPlayerSettings(self._binders.PlayerSettings, player)
|
|
55
102
|
end
|
|
56
103
|
|
|
104
|
+
--[=[
|
|
105
|
+
Promises the player's settings
|
|
106
|
+
|
|
107
|
+
@param player Player
|
|
108
|
+
@param cancelToken CancellationToken
|
|
109
|
+
@return Promise<PlayerSettingsClient>
|
|
110
|
+
]=]
|
|
57
111
|
function SettingsServiceClient:PromisePlayerSettings(player, cancelToken)
|
|
58
112
|
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
59
113
|
|
|
@@ -8,6 +8,8 @@ local BaseObject = require("BaseObject")
|
|
|
8
8
|
local PlayerSettingsUtils = require("PlayerSettingsUtils")
|
|
9
9
|
local SettingsBindersServer = require("SettingsBindersServer")
|
|
10
10
|
local PlayerDataStoreService = require("PlayerDataStoreService")
|
|
11
|
+
local DataStoreStringUtils = require("DataStoreStringUtils")
|
|
12
|
+
local PlayerSettingsConstants = require("PlayerSettingsConstants")
|
|
11
13
|
|
|
12
14
|
local PlayerHasSettings = setmetatable({}, BaseObject)
|
|
13
15
|
PlayerHasSettings.ClassName = "PlayerHasSettings"
|
|
@@ -64,7 +66,21 @@ function PlayerHasSettings:_handleAttributeChanged(subStore, attributeName)
|
|
|
64
66
|
|
|
65
67
|
-- Write the new value
|
|
66
68
|
local settingName = PlayerSettingsUtils.getSettingName(attributeName)
|
|
69
|
+
if not DataStoreStringUtils.isValidUTF8(settingName) then
|
|
70
|
+
warn(string.format("[PlayerHasSettings] - Bad settingName %q, cannot save", settingName))
|
|
71
|
+
return
|
|
72
|
+
end
|
|
73
|
+
|
|
67
74
|
local newValue = PlayerSettingsUtils.decodeForAttribute(self._settings:GetAttribute(attributeName))
|
|
75
|
+
|
|
76
|
+
if type(newValue) == "string" then
|
|
77
|
+
if (#settingName + #newValue) > PlayerSettingsConstants.MAX_SETTINGS_LENGTH then
|
|
78
|
+
warn(string.format("[PlayerSettingsClient.SetValue] - Setting is too long for %q. Cannot save.", settingName))
|
|
79
|
+
return
|
|
80
|
+
end
|
|
81
|
+
-- TODO: JSON encode and check length for ther scenarios
|
|
82
|
+
end
|
|
83
|
+
|
|
68
84
|
subStore:Store(settingName, newValue)
|
|
69
85
|
end
|
|
70
86
|
|
|
@@ -8,6 +8,7 @@ local PlayerSettingsBase = require("PlayerSettingsBase")
|
|
|
8
8
|
local PlayerSettingsConstants = require("PlayerSettingsConstants")
|
|
9
9
|
local PlayerSettingsUtils = require("PlayerSettingsUtils")
|
|
10
10
|
local SettingRegistryServiceShared = require("SettingRegistryServiceShared")
|
|
11
|
+
local DataStoreStringUtils = require("DataStoreStringUtils")
|
|
11
12
|
|
|
12
13
|
local PlayerSettings = setmetatable({}, PlayerSettingsBase)
|
|
13
14
|
PlayerSettings.ClassName = "PlayerSettings"
|
|
@@ -42,12 +43,25 @@ function PlayerSettings.new(obj, serviceBag)
|
|
|
42
43
|
end
|
|
43
44
|
|
|
44
45
|
function PlayerSettings:EnsureInitialized(settingName, defaultValue)
|
|
46
|
+
assert(DataStoreStringUtils.isValidUTF8(settingName), "Bad settingName")
|
|
45
47
|
assert(defaultValue ~= nil, "defaultValue cannot be nil")
|
|
46
48
|
|
|
47
49
|
local attributeName = PlayerSettingsUtils.getAttributeName(settingName)
|
|
48
50
|
|
|
51
|
+
-- Paranoid UTF8 check. Don't even initialize this setting.
|
|
52
|
+
if type(defaultValue) == "string" then
|
|
53
|
+
assert(DataStoreStringUtils.isValidUTF8(defaultValue), "Bad UTF8 defaultValue")
|
|
54
|
+
end
|
|
55
|
+
|
|
49
56
|
if self._obj:GetAttribute(attributeName) == nil then
|
|
50
|
-
|
|
57
|
+
local encoded = PlayerSettingsUtils.encodeForAttribute(defaultValue)
|
|
58
|
+
|
|
59
|
+
-- Paranoid UTF8 check
|
|
60
|
+
if type(encoded) == "string" then
|
|
61
|
+
assert(DataStoreStringUtils.isValidUTF8(defaultValue), "Bad UTF8 defaultValue")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
self._obj:SetAttribute(attributeName, encoded)
|
|
51
65
|
end
|
|
52
66
|
end
|
|
53
67
|
|
|
@@ -67,6 +81,12 @@ function PlayerSettings:_setSettings(settingsMap)
|
|
|
67
81
|
for settingName, value in pairs(settingsMap) do
|
|
68
82
|
assert(type(settingName) == "string", "Bad key")
|
|
69
83
|
|
|
84
|
+
-- Avoid even letting these be set.
|
|
85
|
+
if not DataStoreStringUtils.isValidUTF8(settingName) then
|
|
86
|
+
warn("[PlayerSettings] - Bad UTF8 settingName. Skipping setting.")
|
|
87
|
+
continue
|
|
88
|
+
end
|
|
89
|
+
|
|
70
90
|
local attributeName = PlayerSettingsUtils.getAttributeName(settingName)
|
|
71
91
|
|
|
72
92
|
if self._obj:GetAttribute(attributeName) == nil then
|
|
@@ -74,8 +94,32 @@ function PlayerSettings:_setSettings(settingsMap)
|
|
|
74
94
|
continue
|
|
75
95
|
end
|
|
76
96
|
|
|
97
|
+
-- Paranoid UTF8 check. Avoid letting this value be set.
|
|
98
|
+
if type(value) == "string" then
|
|
99
|
+
if not DataStoreStringUtils.isValidUTF8(value) then
|
|
100
|
+
warn(string.format("[PlayerSettings] - Bad UTF8 value setting value for %q. Skipping setting.", settingName))
|
|
101
|
+
continue
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
77
105
|
local decoded = PlayerSettingsUtils.decodeForNetwork(value)
|
|
78
|
-
|
|
106
|
+
local encodedAttribute = PlayerSettingsUtils.encodeForAttribute(decoded)
|
|
107
|
+
|
|
108
|
+
if type(encodedAttribute) == "string" then
|
|
109
|
+
-- Paranoid UTF8 check. Avoid letting this value be set.
|
|
110
|
+
if not DataStoreStringUtils.isValidUTF8(encodedAttribute) then
|
|
111
|
+
warn(string.format("[PlayerSettings] - Bad UTF8 encodedAttribute value for %q. Skipping setting.", settingName))
|
|
112
|
+
continue
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
-- Paranoid length check. One setting could prevent all from saving if we overflow our save limit.
|
|
116
|
+
if (#encodedAttribute + #settingName) > PlayerSettingsConstants.MAX_SETTINGS_LENGTH then
|
|
117
|
+
warn(string.format("[PlayerSettings] - Setting %q is too long. Skipping setting.", settingName))
|
|
118
|
+
continue
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
self._obj:SetAttribute(attributeName, encodedAttribute)
|
|
79
123
|
end
|
|
80
124
|
end
|
|
81
125
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
--[=[
|
|
2
|
+
Base class for player settings.
|
|
3
|
+
|
|
2
4
|
@class PlayerSettingsBase
|
|
3
5
|
]=]
|
|
4
6
|
|
|
@@ -9,13 +11,21 @@ local PlayerSettingsUtils = require("PlayerSettingsUtils")
|
|
|
9
11
|
local RxAttributeUtils = require("RxAttributeUtils")
|
|
10
12
|
local SettingDefinition = require("SettingDefinition")
|
|
11
13
|
local Rx = require("Rx")
|
|
14
|
+
local DataStoreStringUtils = require("DataStoreStringUtils")
|
|
12
15
|
|
|
13
16
|
local PlayerSettingsBase = setmetatable({}, BaseObject)
|
|
14
17
|
PlayerSettingsBase.ClassName = "PlayerSettingsBase"
|
|
15
18
|
PlayerSettingsBase.__index = PlayerSettingsBase
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
--[=[
|
|
21
|
+
Base class for player settings
|
|
22
|
+
|
|
23
|
+
@param folder Folder
|
|
24
|
+
@param serviceBag ServiceBag
|
|
25
|
+
@return PlayerSettingsBase
|
|
26
|
+
]=]
|
|
27
|
+
function PlayerSettingsBase.new(folder, serviceBag)
|
|
28
|
+
local self = setmetatable(BaseObject.new(folder), PlayerSettingsBase)
|
|
19
29
|
|
|
20
30
|
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
21
31
|
|
|
@@ -65,6 +75,7 @@ end
|
|
|
65
75
|
function PlayerSettingsBase:GetValue(settingName, defaultValue)
|
|
66
76
|
assert(type(settingName) == "string", "Bad settingName")
|
|
67
77
|
assert(defaultValue ~= nil, "defaultValue cannot be nil")
|
|
78
|
+
assert(DataStoreStringUtils.isValidUTF8(settingName), "Bad settingName")
|
|
68
79
|
|
|
69
80
|
local attributeName = PlayerSettingsUtils.getAttributeName(settingName)
|
|
70
81
|
|
|
@@ -87,6 +98,7 @@ end
|
|
|
87
98
|
]=]
|
|
88
99
|
function PlayerSettingsBase:SetValue(settingName, value)
|
|
89
100
|
assert(type(settingName) == "string", "Bad settingName")
|
|
101
|
+
assert(DataStoreStringUtils.isValidUTF8(settingName), "Bad settingName")
|
|
90
102
|
|
|
91
103
|
local attributeName = PlayerSettingsUtils.getAttributeName(settingName)
|
|
92
104
|
|
|
@@ -103,6 +115,7 @@ end
|
|
|
103
115
|
function PlayerSettingsBase:ObserveValue(settingName, defaultValue)
|
|
104
116
|
assert(type(settingName) == "string", "Bad settingName")
|
|
105
117
|
assert(defaultValue ~= nil, "defaultValue cannot be nil")
|
|
118
|
+
assert(DataStoreStringUtils.isValidUTF8(settingName), "Bad settingName")
|
|
106
119
|
|
|
107
120
|
local attributeName = PlayerSettingsUtils.getAttributeName(settingName)
|
|
108
121
|
|
|
@@ -114,7 +127,16 @@ function PlayerSettingsBase:ObserveValue(settingName, defaultValue)
|
|
|
114
127
|
})
|
|
115
128
|
end
|
|
116
129
|
|
|
130
|
+
--[=[
|
|
131
|
+
Restores the default value for the setting
|
|
132
|
+
|
|
133
|
+
@param settingName string
|
|
134
|
+
@param defaultValue T
|
|
135
|
+
]=]
|
|
117
136
|
function PlayerSettingsBase:RestoreDefault(settingName, defaultValue)
|
|
137
|
+
assert(type(settingName) == "string", "Bad settingName")
|
|
138
|
+
assert(DataStoreStringUtils.isValidUTF8(settingName), "Bad settingName")
|
|
139
|
+
|
|
118
140
|
-- TODO: Maybe something more sophisticated?
|
|
119
141
|
self:SetValue(settingName, defaultValue)
|
|
120
142
|
end
|
|
@@ -128,6 +150,7 @@ end
|
|
|
128
150
|
function PlayerSettingsBase:EnsureInitialized(settingName, defaultValue)
|
|
129
151
|
assert(type(settingName) == "string", "Bad settingName")
|
|
130
152
|
assert(defaultValue ~= nil, "defaultValue cannot be nil")
|
|
153
|
+
assert(DataStoreStringUtils.isValidUTF8(settingName), "Bad settingName")
|
|
131
154
|
|
|
132
155
|
-- noop
|
|
133
156
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
--[=[
|
|
2
|
+
Utility helpers to work with settings.
|
|
3
|
+
|
|
2
4
|
@class PlayerSettingsUtils
|
|
3
5
|
]=]
|
|
4
6
|
|
|
@@ -11,9 +13,16 @@ local BinderUtils = require("BinderUtils")
|
|
|
11
13
|
local Binder = require("Binder")
|
|
12
14
|
local RxStateStackUtils = require("RxStateStackUtils")
|
|
13
15
|
local EnumUtils = require("EnumUtils")
|
|
16
|
+
local DataStoreStringUtils = require("DataStoreStringUtils")
|
|
14
17
|
|
|
15
18
|
local PlayerSettingsUtils = {}
|
|
16
19
|
|
|
20
|
+
--[=[
|
|
21
|
+
Creates a new player settings
|
|
22
|
+
|
|
23
|
+
@param binder Binder<PlayerSettings>
|
|
24
|
+
@return Folder
|
|
25
|
+
]=]
|
|
17
26
|
function PlayerSettingsUtils.create(binder)
|
|
18
27
|
assert(Binder.isBinder(binder), "No binder")
|
|
19
28
|
|
|
@@ -25,6 +34,13 @@ function PlayerSettingsUtils.create(binder)
|
|
|
25
34
|
return playerSettings
|
|
26
35
|
end
|
|
27
36
|
|
|
37
|
+
--[=[
|
|
38
|
+
Observe a player settings for a player.
|
|
39
|
+
|
|
40
|
+
@param binder Binder<PlayerSettings>
|
|
41
|
+
@param player Player
|
|
42
|
+
@return Observable<PlayerSettings>
|
|
43
|
+
]=]
|
|
28
44
|
function PlayerSettingsUtils.observePlayerSettingsBrio(binder, player)
|
|
29
45
|
assert(Binder.isBinder(binder), "No binder")
|
|
30
46
|
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
@@ -32,12 +48,26 @@ function PlayerSettingsUtils.observePlayerSettingsBrio(binder, player)
|
|
|
32
48
|
return RxBinderUtils.observeBoundChildClassBrio(binder, player)
|
|
33
49
|
end
|
|
34
50
|
|
|
51
|
+
--[=[
|
|
52
|
+
Observe a player's latest settings
|
|
53
|
+
|
|
54
|
+
@param binder Binder<PlayerSettings>
|
|
55
|
+
@param player Player
|
|
56
|
+
@return Observable<PlayerSettings>
|
|
57
|
+
]=]
|
|
35
58
|
function PlayerSettingsUtils.observePlayerSettings(binder, player)
|
|
36
59
|
return RxBinderUtils.observeBoundChildClassBrio(binder, player):Pipe({
|
|
37
60
|
RxStateStackUtils.topOfStack()
|
|
38
61
|
})
|
|
39
62
|
end
|
|
40
63
|
|
|
64
|
+
--[=[
|
|
65
|
+
Gets a player's latest settings
|
|
66
|
+
|
|
67
|
+
@param binder Binder<PlayerSettings>
|
|
68
|
+
@param player Player
|
|
69
|
+
@return PlayerSettings
|
|
70
|
+
]=]
|
|
41
71
|
function PlayerSettingsUtils.getPlayerSettings(binder, player)
|
|
42
72
|
assert(Binder.isBinder(binder), "No binder")
|
|
43
73
|
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
@@ -45,25 +75,50 @@ function PlayerSettingsUtils.getPlayerSettings(binder, player)
|
|
|
45
75
|
return BinderUtils.findFirstChild(binder, player)
|
|
46
76
|
end
|
|
47
77
|
|
|
78
|
+
--[=[
|
|
79
|
+
Gets the attribute name for a setting
|
|
80
|
+
|
|
81
|
+
@param settingName string
|
|
82
|
+
@return string
|
|
83
|
+
]=]
|
|
48
84
|
function PlayerSettingsUtils.getAttributeName(settingName)
|
|
49
85
|
assert(type(settingName) == "string", "Bad settingName")
|
|
86
|
+
assert(DataStoreStringUtils.isValidUTF8(settingName), "Bad settingName")
|
|
50
87
|
|
|
51
88
|
return PlayerSettingsConstants.SETTING_ATTRIBUTE_PREFIX .. settingName
|
|
52
89
|
end
|
|
53
90
|
|
|
91
|
+
--[=[
|
|
92
|
+
Gets the settings name from an attribute. May return a string
|
|
93
|
+
that cannot be loaded into datastore.
|
|
94
|
+
|
|
95
|
+
@param attributeName string
|
|
96
|
+
@return string
|
|
97
|
+
]=]
|
|
54
98
|
function PlayerSettingsUtils.getSettingName(attributeName)
|
|
55
99
|
assert(type(attributeName) == "string", "Bad attributeName")
|
|
56
100
|
|
|
57
|
-
|
|
58
|
-
return attributeName
|
|
101
|
+
return String.removePrefix(attributeName, PlayerSettingsConstants.SETTING_ATTRIBUTE_PREFIX)
|
|
59
102
|
end
|
|
60
103
|
|
|
104
|
+
--[=[
|
|
105
|
+
Returns true if the attribute name is a settings attribute
|
|
106
|
+
|
|
107
|
+
@param attributeName string
|
|
108
|
+
@return string
|
|
109
|
+
]=]
|
|
61
110
|
function PlayerSettingsUtils.isSettingAttribute(attributeName)
|
|
62
111
|
assert(type(attributeName) == "string", "Bad attributeName")
|
|
63
112
|
|
|
64
113
|
return String.startsWith(attributeName, PlayerSettingsConstants.SETTING_ATTRIBUTE_PREFIX)
|
|
65
114
|
end
|
|
66
115
|
|
|
116
|
+
--[=[
|
|
117
|
+
Encodes a given value for network transfer
|
|
118
|
+
|
|
119
|
+
@param settingValue any
|
|
120
|
+
@return any
|
|
121
|
+
]=]
|
|
67
122
|
function PlayerSettingsUtils.encodeForNetwork(settingValue)
|
|
68
123
|
assert(settingValue ~= "<NIL_SETTING_VALUE>", "Cannot have setting as <NIL_SETTING_VALUE>")
|
|
69
124
|
|
|
@@ -76,6 +131,12 @@ function PlayerSettingsUtils.encodeForNetwork(settingValue)
|
|
|
76
131
|
end
|
|
77
132
|
end
|
|
78
133
|
|
|
134
|
+
--[=[
|
|
135
|
+
Decodes a given value from network transfer
|
|
136
|
+
|
|
137
|
+
@param settingValue any
|
|
138
|
+
@return any
|
|
139
|
+
]=]
|
|
79
140
|
function PlayerSettingsUtils.decodeForNetwork(settingValue)
|
|
80
141
|
if settingValue == "<NIL_SETTING_VALUE>" then
|
|
81
142
|
return nil
|
|
@@ -86,6 +147,12 @@ function PlayerSettingsUtils.decodeForNetwork(settingValue)
|
|
|
86
147
|
end
|
|
87
148
|
end
|
|
88
149
|
|
|
150
|
+
--[=[
|
|
151
|
+
Decodes a given value for attribute storage
|
|
152
|
+
|
|
153
|
+
@param settingValue any
|
|
154
|
+
@return any
|
|
155
|
+
]=]
|
|
89
156
|
function PlayerSettingsUtils.decodeForAttribute(settingValue)
|
|
90
157
|
if EnumUtils.isEncodedEnum(settingValue) then
|
|
91
158
|
return EnumUtils.decodeFromString(settingValue)
|
|
@@ -94,6 +161,12 @@ function PlayerSettingsUtils.decodeForAttribute(settingValue)
|
|
|
94
161
|
end
|
|
95
162
|
end
|
|
96
163
|
|
|
164
|
+
--[=[
|
|
165
|
+
Encodes a given value for attribute storage
|
|
166
|
+
|
|
167
|
+
@param settingValue any
|
|
168
|
+
@return any
|
|
169
|
+
]=]
|
|
97
170
|
function PlayerSettingsUtils.encodeForAttribute(settingValue)
|
|
98
171
|
if typeof(settingValue) == "EnumItem" then
|
|
99
172
|
return EnumUtils.encodeAsString(settingValue)
|
|
@@ -102,5 +175,4 @@ function PlayerSettingsUtils.encodeForAttribute(settingValue)
|
|
|
102
175
|
end
|
|
103
176
|
end
|
|
104
177
|
|
|
105
|
-
|
|
106
178
|
return PlayerSettingsUtils
|
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
--[=[
|
|
2
|
+
These settings definitions are used to define a setting and register them on both the client and server. See
|
|
3
|
+
[SettingDefinitionProvider] for more details on grouping these.
|
|
4
|
+
|
|
5
|
+
Notably a setting is basically anything on the client that can be stored on the server by the client, and that
|
|
6
|
+
relatively minimal validation is required upon. This can be both user-set settings, as well as very temporary
|
|
7
|
+
data.
|
|
8
|
+
|
|
9
|
+
```lua
|
|
10
|
+
local SettingDefinition = require("SettingDefinition")
|
|
11
|
+
|
|
12
|
+
return require("SettingDefinitionProvider").new({
|
|
13
|
+
SettingDefinition.new("LastTimeUpdateSeen", 0);
|
|
14
|
+
SettingDefinition.new("LastTimeShopSeen", 0);
|
|
15
|
+
})
|
|
16
|
+
```
|
|
17
|
+
|
|
2
18
|
@class SettingDefinition
|
|
3
19
|
]=]
|
|
4
20
|
|
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
--[=[
|
|
2
|
+
Provides settings in bulk, and can be initialized by a [ServiceBag]. See [SettingDefinition] for
|
|
3
|
+
more details on how to use this.
|
|
4
|
+
|
|
5
|
+
:::tip
|
|
6
|
+
These settings providers should be used on both the client and the server. On the client, these
|
|
7
|
+
are registered with the [SettingRegistryServiceShared] so that they can be shown in UI automatically
|
|
8
|
+
if desired.
|
|
9
|
+
|
|
10
|
+
On the server, these are registered with [SettingRegistryServiceShared] and then are checked before
|
|
11
|
+
arbitrary data can e sent.
|
|
12
|
+
:::
|
|
13
|
+
|
|
14
|
+
```lua
|
|
15
|
+
local SettingDefinition = require("SettingDefinition")
|
|
16
|
+
|
|
17
|
+
return require("SettingDefinitionProvider").new({
|
|
18
|
+
SettingDefinition.new("KeyBinding", Enum.KeyCode.X);
|
|
19
|
+
SettingDefinition.new("CameraShake", true);
|
|
20
|
+
SettingDefinition.new("CameraSensitivity", 1);
|
|
21
|
+
})
|
|
22
|
+
```
|
|
23
|
+
|
|
2
24
|
@class SettingDefinitionProvider
|
|
3
25
|
]=]
|
|
4
26
|
|
|
@@ -12,6 +34,22 @@ SettingDefinitionProvider.ClassName = "SettingDefinitionProvider"
|
|
|
12
34
|
SettingDefinitionProvider.ServiceName = "SettingDefinitionProvider"
|
|
13
35
|
SettingDefinitionProvider.__index = SettingDefinitionProvider
|
|
14
36
|
|
|
37
|
+
--[=[
|
|
38
|
+
Constructs a new provider with a list of [SettingDefinition]'s.
|
|
39
|
+
|
|
40
|
+
```lua
|
|
41
|
+
local SettingDefinition = require("SettingDefinition")
|
|
42
|
+
|
|
43
|
+
return require("SettingDefinitionProvider").new({
|
|
44
|
+
SettingDefinition.new("KeyBinding", Enum.KeyCode.X);
|
|
45
|
+
SettingDefinition.new("CameraShake", true);
|
|
46
|
+
SettingDefinition.new("CameraSensitivity", 1);
|
|
47
|
+
})
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
@param settingDefinitions { SettingDefinition }
|
|
51
|
+
@return SettingDefinitionProvider
|
|
52
|
+
]=]
|
|
15
53
|
function SettingDefinitionProvider.new(settingDefinitions)
|
|
16
54
|
local self = setmetatable({}, SettingDefinitionProvider)
|
|
17
55
|
|
|
@@ -26,6 +64,11 @@ function SettingDefinitionProvider.new(settingDefinitions)
|
|
|
26
64
|
return self
|
|
27
65
|
end
|
|
28
66
|
|
|
67
|
+
--[=[
|
|
68
|
+
Initializes the provider, storing the data in [SettingRegistryServiceShared]
|
|
69
|
+
|
|
70
|
+
@param serviceBag ServiceBag
|
|
71
|
+
]=]
|
|
29
72
|
function SettingDefinitionProvider:Init(serviceBag)
|
|
30
73
|
assert(serviceBag, "No serviceBag")
|
|
31
74
|
assert(not self._maid, "Already initialized")
|
|
@@ -38,16 +81,47 @@ function SettingDefinitionProvider:Init(serviceBag)
|
|
|
38
81
|
end
|
|
39
82
|
end
|
|
40
83
|
|
|
84
|
+
--[=[
|
|
85
|
+
Starts the provider. Empty.
|
|
86
|
+
]=]
|
|
41
87
|
function SettingDefinitionProvider:Start()
|
|
42
88
|
-- Empty, to prevent us from erroring on service bag init
|
|
43
89
|
end
|
|
44
90
|
|
|
91
|
+
--[=[
|
|
92
|
+
Returns the setting definition
|
|
93
|
+
|
|
94
|
+
@return { SettingDefinition }
|
|
95
|
+
]=]
|
|
45
96
|
function SettingDefinitionProvider:GetSettingDefinitions()
|
|
46
97
|
return self._settingDefinitions
|
|
47
98
|
end
|
|
48
99
|
|
|
100
|
+
--[=[
|
|
101
|
+
You can index the provider to get a setting. For example
|
|
102
|
+
|
|
103
|
+
```lua
|
|
104
|
+
local SettingDefinition = require("SettingDefinition")
|
|
105
|
+
|
|
106
|
+
local provider = require("SettingDefinitionProvider").new({
|
|
107
|
+
SettingDefinition.new("KeyBinding", Enum.KeyCode.X);
|
|
108
|
+
SettingDefinition.new("CameraShake", true);
|
|
109
|
+
SettingDefinition.new("CameraSensitivity", 1);
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
local service = serviceBag:GetService(provider)
|
|
113
|
+
|
|
114
|
+
-- Write a setting
|
|
115
|
+
service.CamaraShake:GetLocalPlayerSettingProperty(serviceBag).Value = false
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
@param index string
|
|
119
|
+
@return SettingDefinition
|
|
120
|
+
]=]
|
|
49
121
|
function SettingDefinitionProvider:__index(index)
|
|
50
|
-
if
|
|
122
|
+
if index == nil then
|
|
123
|
+
error("[SettingDefinitionProvider] - Cannot index provider with nil value")
|
|
124
|
+
elseif SettingDefinitionProvider[index] then
|
|
51
125
|
return SettingDefinitionProvider[index]
|
|
52
126
|
elseif index == "_lookup" or index == "_settingDefinitions" or index == "_maid" then
|
|
53
127
|
return rawget(self, index)
|
|
@@ -64,10 +138,21 @@ function SettingDefinitionProvider:__index(index)
|
|
|
64
138
|
end
|
|
65
139
|
end
|
|
66
140
|
|
|
141
|
+
--[=[
|
|
142
|
+
Gets a new setting definition if it exists
|
|
143
|
+
|
|
144
|
+
@param settingName string
|
|
145
|
+
@return SettingDefinition
|
|
146
|
+
]=]
|
|
67
147
|
function SettingDefinitionProvider:Get(settingName)
|
|
148
|
+
assert(type(settingName) == "string", "Bad settingName")
|
|
149
|
+
|
|
68
150
|
return self._lookup[settingName]
|
|
69
151
|
end
|
|
70
152
|
|
|
153
|
+
--[=[
|
|
154
|
+
Cleans up the setting registration
|
|
155
|
+
]=]
|
|
71
156
|
function SettingDefinitionProvider:Destroy()
|
|
72
157
|
self._maid:DoCleaning()
|
|
73
158
|
end
|
|
@@ -11,6 +11,14 @@ local SettingProperty = {}
|
|
|
11
11
|
SettingProperty.ClassName = "SettingProperty"
|
|
12
12
|
SettingProperty.__index = SettingProperty
|
|
13
13
|
|
|
14
|
+
--[=[
|
|
15
|
+
Constructs a new SettingProperty.
|
|
16
|
+
|
|
17
|
+
@param serviceBag ServiceBag
|
|
18
|
+
@param player Player
|
|
19
|
+
@param definition SettingDefinition
|
|
20
|
+
@return SettingProperty<T>
|
|
21
|
+
]=]
|
|
14
22
|
function SettingProperty.new(serviceBag, player, definition)
|
|
15
23
|
local self = setmetatable({}, SettingProperty)
|
|
16
24
|
|
|
@@ -27,6 +35,10 @@ function SettingProperty.new(serviceBag, player, definition)
|
|
|
27
35
|
return self
|
|
28
36
|
end
|
|
29
37
|
|
|
38
|
+
--[=[
|
|
39
|
+
Observes the value of the setting property
|
|
40
|
+
@return Observable<T>
|
|
41
|
+
]=]
|
|
30
42
|
function SettingProperty:Observe()
|
|
31
43
|
return self:_observePlayerSettings():Pipe({
|
|
32
44
|
Rx.where(function(settings)
|
|
@@ -85,15 +97,29 @@ function SettingProperty:__newindex(index, value)
|
|
|
85
97
|
end
|
|
86
98
|
end
|
|
87
99
|
|
|
100
|
+
--[=[
|
|
101
|
+
Sets the value of the setting property. Will warn if it cannot do so.
|
|
102
|
+
|
|
103
|
+
:::tip
|
|
104
|
+
Use [PromiseSetValue] to ensure value is set.
|
|
105
|
+
:::
|
|
106
|
+
|
|
107
|
+
@param value T
|
|
108
|
+
]=]
|
|
88
109
|
function SettingProperty:SetValue(value)
|
|
89
110
|
local settings = self:_getPlayerSettings()
|
|
90
111
|
if settings then
|
|
91
112
|
settings:SetValue(self._definition:GetSettingName(), value)
|
|
92
113
|
else
|
|
93
|
-
warn("Cannot set setting value. Use :PromiseSetValue() to ensure value is set after load.")
|
|
114
|
+
warn("[SettingProperty.SetValue] - Cannot set setting value. Use :PromiseSetValue() to ensure value is set after load.")
|
|
94
115
|
end
|
|
95
116
|
end
|
|
96
117
|
|
|
118
|
+
--[=[
|
|
119
|
+
Promises the value of the setting once it's loaded.
|
|
120
|
+
|
|
121
|
+
@return Promise<T>
|
|
122
|
+
]=]
|
|
97
123
|
function SettingProperty:PromiseValue()
|
|
98
124
|
return self:_promisePlayerSettings()
|
|
99
125
|
:Then(function(playerSettings)
|
|
@@ -101,6 +127,12 @@ function SettingProperty:PromiseValue()
|
|
|
101
127
|
end)
|
|
102
128
|
end
|
|
103
129
|
|
|
130
|
+
--[=[
|
|
131
|
+
Promises to set the value
|
|
132
|
+
|
|
133
|
+
@param value T
|
|
134
|
+
@return Promise
|
|
135
|
+
]=]
|
|
104
136
|
function SettingProperty:PromiseSetValue(value)
|
|
105
137
|
return self:_promisePlayerSettings()
|
|
106
138
|
:Then(function(playerSettings)
|
|
@@ -108,15 +140,33 @@ function SettingProperty:PromiseSetValue(value)
|
|
|
108
140
|
end)
|
|
109
141
|
end
|
|
110
142
|
|
|
143
|
+
--[=[
|
|
144
|
+
Restores the setting to the default value
|
|
145
|
+
]=]
|
|
111
146
|
function SettingProperty:RestoreDefault()
|
|
112
147
|
local settings = self:_getPlayerSettings()
|
|
113
148
|
if settings then
|
|
114
149
|
settings:RestoreDefault(self._definition:GetSettingName(), self._definition:GetDefaultValue())
|
|
115
150
|
else
|
|
116
|
-
warn("Cannot set setting value. Use :
|
|
151
|
+
warn("[SettingProperty.RestoreDefault] - Cannot set setting value. Use :PromiseRestoreDefault() to ensure value is set after load.")
|
|
117
152
|
end
|
|
118
153
|
end
|
|
119
154
|
|
|
155
|
+
--[=[
|
|
156
|
+
Restores the setting to the default value. This is different than setting to the default value
|
|
157
|
+
because it means there is no "user-set" value which could lead to values changing if
|
|
158
|
+
defaults change.
|
|
159
|
+
|
|
160
|
+
@return Promise
|
|
161
|
+
]=]
|
|
162
|
+
function SettingProperty:PromiseRestoreDefault()
|
|
163
|
+
return self:_promisePlayerSettings()
|
|
164
|
+
:Then(function(playerSettings)
|
|
165
|
+
playerSettings:RestoreDefault(self._definition:GetSettingName(), self._definition:GetDefaultValue())
|
|
166
|
+
end)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
|
|
120
170
|
function SettingProperty:_observePlayerSettings()
|
|
121
171
|
return self._bridge:ObservePlayerSettings(self._player)
|
|
122
172
|
end
|
|
@@ -129,6 +179,4 @@ function SettingProperty:_promisePlayerSettings()
|
|
|
129
179
|
return self._bridge:PromisePlayerSettings(self._player)
|
|
130
180
|
end
|
|
131
181
|
|
|
132
|
-
|
|
133
|
-
|
|
134
182
|
return SettingProperty
|
|
@@ -9,39 +9,81 @@ local require = require(script.Parent.loader).load(script)
|
|
|
9
9
|
local ValueObject = require("ValueObject")
|
|
10
10
|
local Rx = require("Rx")
|
|
11
11
|
local ObservableSet = require("ObservableSet")
|
|
12
|
+
local Maid = require("Maid")
|
|
12
13
|
|
|
13
14
|
local SettingRegistryServiceShared = {}
|
|
14
15
|
|
|
16
|
+
--[=[
|
|
17
|
+
Initializes the shared registry service. Should be done via [ServiceBag].
|
|
18
|
+
|
|
19
|
+
@param serviceBag ServiceBag
|
|
20
|
+
]=]
|
|
15
21
|
function SettingRegistryServiceShared:Init(serviceBag)
|
|
16
22
|
assert(not self._serviceBag, "Already initialized")
|
|
17
23
|
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
24
|
+
self._maid = Maid.new()
|
|
18
25
|
|
|
19
26
|
self._settingService = ValueObject.new()
|
|
27
|
+
self._maid:GiveTask(self._settingService)
|
|
28
|
+
|
|
20
29
|
self._settingDefinitions = ObservableSet.new()
|
|
30
|
+
self._maid:GiveTask(self._settingDefinitions)
|
|
21
31
|
end
|
|
22
32
|
|
|
33
|
+
--[=[
|
|
34
|
+
Registers the shared setting service for this bridge
|
|
35
|
+
|
|
36
|
+
@param settingService SettingService
|
|
37
|
+
]=]
|
|
23
38
|
function SettingRegistryServiceShared:RegisterSettingService(settingService)
|
|
24
39
|
self._settingService.Value = settingService
|
|
25
40
|
end
|
|
26
41
|
|
|
42
|
+
--[=[
|
|
43
|
+
Registers settings definitions
|
|
44
|
+
|
|
45
|
+
@param definition SettingDefinition
|
|
46
|
+
@return callback -- Cleanup callback
|
|
47
|
+
]=]
|
|
27
48
|
function SettingRegistryServiceShared:RegisterSettingDefinition(definition)
|
|
28
49
|
assert(definition, "No definition")
|
|
29
50
|
|
|
30
51
|
return self._settingDefinitions:Add(definition)
|
|
31
52
|
end
|
|
32
53
|
|
|
54
|
+
--[=[
|
|
55
|
+
Observes the registered definitions
|
|
56
|
+
|
|
57
|
+
@return Observable<Brio<SettingDefinition>>
|
|
58
|
+
]=]
|
|
33
59
|
function SettingRegistryServiceShared:ObserveRegisteredDefinitionsBrio()
|
|
34
60
|
return self._settingDefinitions:ObserveItemsBrio()
|
|
35
61
|
end
|
|
36
62
|
|
|
63
|
+
--[=[
|
|
64
|
+
Gets the current settings service
|
|
65
|
+
|
|
66
|
+
@return SettingService
|
|
67
|
+
]=]
|
|
37
68
|
function SettingRegistryServiceShared:GetSettingsService()
|
|
38
69
|
return self._settingService.Value
|
|
39
70
|
end
|
|
40
71
|
|
|
72
|
+
--[=[
|
|
73
|
+
Observes the current settings service
|
|
74
|
+
|
|
75
|
+
@return Observable<SettingService>
|
|
76
|
+
]=]
|
|
41
77
|
function SettingRegistryServiceShared:ObserveSettingsService()
|
|
42
78
|
return self._settingService:Observe()
|
|
43
79
|
end
|
|
44
80
|
|
|
81
|
+
--[=[
|
|
82
|
+
Observes the player's settings
|
|
83
|
+
|
|
84
|
+
@param player Player
|
|
85
|
+
@return Observable<PlayerSettingsBase>
|
|
86
|
+
]=]
|
|
45
87
|
function SettingRegistryServiceShared:ObservePlayerSettings(player)
|
|
46
88
|
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
47
89
|
|
|
@@ -56,6 +98,12 @@ function SettingRegistryServiceShared:ObservePlayerSettings(player)
|
|
|
56
98
|
})
|
|
57
99
|
end
|
|
58
100
|
|
|
101
|
+
--[=[
|
|
102
|
+
Promises the player's settings
|
|
103
|
+
|
|
104
|
+
@param player Player
|
|
105
|
+
@return Promise<PlayerSettingsBase>
|
|
106
|
+
]=]
|
|
59
107
|
function SettingRegistryServiceShared:PromisePlayerSettings(player)
|
|
60
108
|
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
61
109
|
|
|
@@ -69,6 +117,12 @@ function SettingRegistryServiceShared:PromisePlayerSettings(player)
|
|
|
69
117
|
end)
|
|
70
118
|
end
|
|
71
119
|
|
|
120
|
+
--[=[
|
|
121
|
+
Gets the player's settings
|
|
122
|
+
|
|
123
|
+
@param player Player
|
|
124
|
+
@return Promise<PlayerSettingsBase>
|
|
125
|
+
]=]
|
|
72
126
|
function SettingRegistryServiceShared:GetPlayerSettings(player)
|
|
73
127
|
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
74
128
|
|
|
@@ -80,4 +134,11 @@ function SettingRegistryServiceShared:GetPlayerSettings(player)
|
|
|
80
134
|
end
|
|
81
135
|
end
|
|
82
136
|
|
|
137
|
+
--[=[
|
|
138
|
+
Cleans up the shared registry service
|
|
139
|
+
]=]
|
|
140
|
+
function SettingRegistryServiceShared:Destroy()
|
|
141
|
+
self._maid:DoCleaning()
|
|
142
|
+
end
|
|
143
|
+
|
|
83
144
|
return SettingRegistryServiceShared
|