roblox-opencode 1.0.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.
Files changed (248) hide show
  1. package/README.md +122 -0
  2. package/commands/setup-game.md +108 -0
  3. package/commands/sync-check.md +53 -0
  4. package/core/roblox-core.md +93 -0
  5. package/dist/server.js +167 -0
  6. package/package.json +35 -0
  7. package/skills/roblox-analytics/SKILL.md +277 -0
  8. package/skills/roblox-analytics/references/event-batcher.luau +75 -0
  9. package/skills/roblox-animation-vfx/SKILL.md +1325 -0
  10. package/skills/roblox-architecture/SKILL.md +863 -0
  11. package/skills/roblox-architecture/references/combat-systems.md +1381 -0
  12. package/skills/roblox-code-review/SKILL.md +687 -0
  13. package/skills/roblox-data/SKILL.md +889 -0
  14. package/skills/roblox-data/references/inventory-systems.md +1729 -0
  15. package/skills/roblox-debug/SKILL.md +99 -0
  16. package/skills/roblox-gui/SKILL.md +1103 -0
  17. package/skills/roblox-gui-fusion/SKILL.md +150 -0
  18. package/skills/roblox-gui-fusion/references/inventory.luau +427 -0
  19. package/skills/roblox-gui-fusion/references/settings-menu.luau +579 -0
  20. package/skills/roblox-gui-fusion/references/shop.luau +411 -0
  21. package/skills/roblox-luau-mastery/SKILL.md +1519 -0
  22. package/skills/roblox-monetization/SKILL.md +1084 -0
  23. package/skills/roblox-monetization/references/process-receipt.luau +131 -0
  24. package/skills/roblox-networking/SKILL.md +669 -0
  25. package/skills/roblox-networking/references/remote-validator.luau +193 -0
  26. package/skills/roblox-publish-checklist/SKILL.md +128 -0
  27. package/skills/roblox-runtime/SKILL.md +753 -0
  28. package/skills/roblox-sharp-edges/SKILL.md +295 -0
  29. package/skills/roblox-sync/SKILL.md +126 -0
  30. package/skills/roblox-testing/SKILL.md +943 -0
  31. package/skills/roblox-tooling/SKILL.md +150 -0
  32. package/vendor/LICENSES/ProfileStore-LICENSE +201 -0
  33. package/vendor/LICENSES/RbxUtil-LICENSE +7 -0
  34. package/vendor/LICENSES/promise-LICENSE +21 -0
  35. package/vendor/LICENSES/t-LICENSE +21 -0
  36. package/vendor/LICENSES/testez-LICENSE +201 -0
  37. package/vendor/README.md +84 -0
  38. package/vendor/fusion/Animation/ExternalTime.luau +84 -0
  39. package/vendor/fusion/Animation/Spring.luau +322 -0
  40. package/vendor/fusion/Animation/Stopwatch.luau +128 -0
  41. package/vendor/fusion/Animation/Tween.luau +187 -0
  42. package/vendor/fusion/Animation/getTweenDuration.luau +27 -0
  43. package/vendor/fusion/Animation/getTweenRatio.luau +47 -0
  44. package/vendor/fusion/Animation/lerpType.luau +164 -0
  45. package/vendor/fusion/Animation/packType.luau +100 -0
  46. package/vendor/fusion/Animation/springCoefficients.luau +80 -0
  47. package/vendor/fusion/Animation/unpackType.luau +103 -0
  48. package/vendor/fusion/Colour/Oklab.luau +70 -0
  49. package/vendor/fusion/Colour/sRGB.luau +55 -0
  50. package/vendor/fusion/External.luau +168 -0
  51. package/vendor/fusion/ExternalDebug.luau +70 -0
  52. package/vendor/fusion/Graph/Observer.luau +114 -0
  53. package/vendor/fusion/Graph/castToGraph.luau +29 -0
  54. package/vendor/fusion/Graph/change.luau +81 -0
  55. package/vendor/fusion/Graph/depend.luau +33 -0
  56. package/vendor/fusion/Graph/evaluate.luau +56 -0
  57. package/vendor/fusion/Instances/Attribute.luau +58 -0
  58. package/vendor/fusion/Instances/AttributeChange.luau +47 -0
  59. package/vendor/fusion/Instances/AttributeOut.luau +63 -0
  60. package/vendor/fusion/Instances/Child.luau +21 -0
  61. package/vendor/fusion/Instances/Children.luau +148 -0
  62. package/vendor/fusion/Instances/Hydrate.luau +33 -0
  63. package/vendor/fusion/Instances/New.luau +53 -0
  64. package/vendor/fusion/Instances/OnChange.luau +50 -0
  65. package/vendor/fusion/Instances/OnEvent.luau +54 -0
  66. package/vendor/fusion/Instances/Out.luau +69 -0
  67. package/vendor/fusion/Instances/applyInstanceProps.luau +149 -0
  68. package/vendor/fusion/Instances/defaultProps.luau +194 -0
  69. package/vendor/fusion/LICENSE +21 -0
  70. package/vendor/fusion/Logging/formatError.luau +49 -0
  71. package/vendor/fusion/Logging/messages.luau +52 -0
  72. package/vendor/fusion/Logging/parseError.luau +25 -0
  73. package/vendor/fusion/Memory/checkLifetime.luau +134 -0
  74. package/vendor/fusion/Memory/deriveScope.luau +24 -0
  75. package/vendor/fusion/Memory/deriveScopeImpl.luau +45 -0
  76. package/vendor/fusion/Memory/doCleanup.luau +79 -0
  77. package/vendor/fusion/Memory/innerScope.luau +34 -0
  78. package/vendor/fusion/Memory/legacyCleanup.luau +18 -0
  79. package/vendor/fusion/Memory/needsDestruction.luau +17 -0
  80. package/vendor/fusion/Memory/poisonScope.luau +34 -0
  81. package/vendor/fusion/Memory/scopePool.luau +55 -0
  82. package/vendor/fusion/Memory/scoped.luau +27 -0
  83. package/vendor/fusion/Memory/whichLivesLonger.luau +75 -0
  84. package/vendor/fusion/RobloxExternal.luau +98 -0
  85. package/vendor/fusion/State/Computed.luau +139 -0
  86. package/vendor/fusion/State/For/Disassembly.luau +211 -0
  87. package/vendor/fusion/State/For/ForTypes.luau +30 -0
  88. package/vendor/fusion/State/For/init.luau +110 -0
  89. package/vendor/fusion/State/ForKeys.luau +94 -0
  90. package/vendor/fusion/State/ForPairs.luau +97 -0
  91. package/vendor/fusion/State/ForValues.luau +94 -0
  92. package/vendor/fusion/State/Value.luau +88 -0
  93. package/vendor/fusion/State/castToState.luau +26 -0
  94. package/vendor/fusion/State/peek.luau +31 -0
  95. package/vendor/fusion/State/updateAll.luau +1 -0
  96. package/vendor/fusion/Types.luau +314 -0
  97. package/vendor/fusion/Utility/Contextual.luau +91 -0
  98. package/vendor/fusion/Utility/Safe.luau +23 -0
  99. package/vendor/fusion/Utility/isSimilar.luau +29 -0
  100. package/vendor/fusion/Utility/merge.luau +35 -0
  101. package/vendor/fusion/Utility/nameOf.luau +35 -0
  102. package/vendor/fusion/Utility/never.luau +14 -0
  103. package/vendor/fusion/Utility/nicknames.luau +11 -0
  104. package/vendor/fusion/Utility/xtypeof.luau +27 -0
  105. package/vendor/fusion/init.luau +82 -0
  106. package/vendor/profilestore/init.luau +2243 -0
  107. package/vendor/promise/init.luau +1982 -0
  108. package/vendor/rbxutil/buffer-util/Buffer.test.luau +25 -0
  109. package/vendor/rbxutil/buffer-util/BufferReader.luau +228 -0
  110. package/vendor/rbxutil/buffer-util/BufferWriter.luau +269 -0
  111. package/vendor/rbxutil/buffer-util/DataTypeBuffer.luau +223 -0
  112. package/vendor/rbxutil/buffer-util/Types.luau +60 -0
  113. package/vendor/rbxutil/buffer-util/index.d.ts +153 -0
  114. package/vendor/rbxutil/buffer-util/init.luau +41 -0
  115. package/vendor/rbxutil/buffer-util/package.json +16 -0
  116. package/vendor/rbxutil/buffer-util/wally.toml +9 -0
  117. package/vendor/rbxutil/comm/Client/ClientComm.luau +232 -0
  118. package/vendor/rbxutil/comm/Client/ClientRemoteProperty.luau +156 -0
  119. package/vendor/rbxutil/comm/Client/ClientRemoteSignal.luau +109 -0
  120. package/vendor/rbxutil/comm/Client/init.luau +135 -0
  121. package/vendor/rbxutil/comm/Server/RemoteProperty.luau +295 -0
  122. package/vendor/rbxutil/comm/Server/RemoteSignal.luau +211 -0
  123. package/vendor/rbxutil/comm/Server/ServerComm.luau +211 -0
  124. package/vendor/rbxutil/comm/Server/init.luau +140 -0
  125. package/vendor/rbxutil/comm/Types.luau +18 -0
  126. package/vendor/rbxutil/comm/Util.luau +27 -0
  127. package/vendor/rbxutil/comm/init.luau +35 -0
  128. package/vendor/rbxutil/comm/wally.toml +13 -0
  129. package/vendor/rbxutil/component/init.luau +759 -0
  130. package/vendor/rbxutil/component/init.test.luau +311 -0
  131. package/vendor/rbxutil/component/wally.toml +14 -0
  132. package/vendor/rbxutil/concur/init.luau +542 -0
  133. package/vendor/rbxutil/concur/init.test.luau +364 -0
  134. package/vendor/rbxutil/concur/wally.toml +8 -0
  135. package/vendor/rbxutil/enum-list/init.luau +101 -0
  136. package/vendor/rbxutil/enum-list/init.test.luau +91 -0
  137. package/vendor/rbxutil/enum-list/wally.toml +8 -0
  138. package/vendor/rbxutil/find/index.d.ts +20 -0
  139. package/vendor/rbxutil/find/init.luau +44 -0
  140. package/vendor/rbxutil/find/package.json +17 -0
  141. package/vendor/rbxutil/find/wally.toml +8 -0
  142. package/vendor/rbxutil/input/Gamepad.luau +559 -0
  143. package/vendor/rbxutil/input/Keyboard.luau +124 -0
  144. package/vendor/rbxutil/input/Mouse.luau +278 -0
  145. package/vendor/rbxutil/input/PreferredInput.luau +91 -0
  146. package/vendor/rbxutil/input/Touch.luau +120 -0
  147. package/vendor/rbxutil/input/init.luau +33 -0
  148. package/vendor/rbxutil/input/wally.toml +12 -0
  149. package/vendor/rbxutil/loader/index.d.ts +15 -0
  150. package/vendor/rbxutil/loader/init.luau +137 -0
  151. package/vendor/rbxutil/loader/wally.toml +8 -0
  152. package/vendor/rbxutil/log/index.d.ts +38 -0
  153. package/vendor/rbxutil/log/init.luau +746 -0
  154. package/vendor/rbxutil/log/wally.toml +8 -0
  155. package/vendor/rbxutil/net/init.luau +190 -0
  156. package/vendor/rbxutil/net/wally.toml +8 -0
  157. package/vendor/rbxutil/option/index.d.ts +44 -0
  158. package/vendor/rbxutil/option/init.luau +489 -0
  159. package/vendor/rbxutil/option/init.test.luau +342 -0
  160. package/vendor/rbxutil/option/wally.toml +8 -0
  161. package/vendor/rbxutil/pid/index.d.ts +53 -0
  162. package/vendor/rbxutil/pid/init.luau +195 -0
  163. package/vendor/rbxutil/pid/package.json +16 -0
  164. package/vendor/rbxutil/pid/wally.toml +9 -0
  165. package/vendor/rbxutil/quaternion/index.d.ts +117 -0
  166. package/vendor/rbxutil/quaternion/init.luau +570 -0
  167. package/vendor/rbxutil/quaternion/package.json +16 -0
  168. package/vendor/rbxutil/quaternion/wally.toml +9 -0
  169. package/vendor/rbxutil/query/index.d.ts +43 -0
  170. package/vendor/rbxutil/query/init.luau +117 -0
  171. package/vendor/rbxutil/query/package.json +18 -0
  172. package/vendor/rbxutil/query/wally.toml +9 -0
  173. package/vendor/rbxutil/sequent/index.d.ts +28 -0
  174. package/vendor/rbxutil/sequent/init.luau +340 -0
  175. package/vendor/rbxutil/sequent/package.json +16 -0
  176. package/vendor/rbxutil/sequent/wally.toml +9 -0
  177. package/vendor/rbxutil/ser/init.luau +175 -0
  178. package/vendor/rbxutil/ser/init.test.luau +50 -0
  179. package/vendor/rbxutil/ser/wally.toml +11 -0
  180. package/vendor/rbxutil/shake/index.d.ts +36 -0
  181. package/vendor/rbxutil/shake/init.luau +532 -0
  182. package/vendor/rbxutil/shake/init.test.luau +267 -0
  183. package/vendor/rbxutil/shake/package.json +16 -0
  184. package/vendor/rbxutil/shake/wally.toml +9 -0
  185. package/vendor/rbxutil/signal/index.d.ts +100 -0
  186. package/vendor/rbxutil/signal/init.luau +432 -0
  187. package/vendor/rbxutil/signal/init.test.luau +190 -0
  188. package/vendor/rbxutil/signal/package.json +17 -0
  189. package/vendor/rbxutil/signal/wally.toml +9 -0
  190. package/vendor/rbxutil/silo/TableWatcher.luau +65 -0
  191. package/vendor/rbxutil/silo/Util.luau +55 -0
  192. package/vendor/rbxutil/silo/init.luau +338 -0
  193. package/vendor/rbxutil/silo/init.test.luau +215 -0
  194. package/vendor/rbxutil/silo/wally.toml +8 -0
  195. package/vendor/rbxutil/spring/index.d.ts +40 -0
  196. package/vendor/rbxutil/spring/init.luau +97 -0
  197. package/vendor/rbxutil/spring/package.json +17 -0
  198. package/vendor/rbxutil/spring/wally.toml +8 -0
  199. package/vendor/rbxutil/stream/index.d.ts +88 -0
  200. package/vendor/rbxutil/stream/init.luau +597 -0
  201. package/vendor/rbxutil/stream/package.json +18 -0
  202. package/vendor/rbxutil/stream/wally.toml +9 -0
  203. package/vendor/rbxutil/streamable/Streamable.luau +202 -0
  204. package/vendor/rbxutil/streamable/StreamableUtil.luau +80 -0
  205. package/vendor/rbxutil/streamable/init.luau +8 -0
  206. package/vendor/rbxutil/streamable/wally.toml +12 -0
  207. package/vendor/rbxutil/symbol/init.luau +56 -0
  208. package/vendor/rbxutil/symbol/init.test.luau +37 -0
  209. package/vendor/rbxutil/symbol/wally.toml +8 -0
  210. package/vendor/rbxutil/table-util/init.luau +938 -0
  211. package/vendor/rbxutil/table-util/init.test.luau +439 -0
  212. package/vendor/rbxutil/table-util/wally.toml +8 -0
  213. package/vendor/rbxutil/task-queue/index.d.ts +27 -0
  214. package/vendor/rbxutil/task-queue/init.luau +97 -0
  215. package/vendor/rbxutil/task-queue/wally.toml +8 -0
  216. package/vendor/rbxutil/timer/index.d.ts +81 -0
  217. package/vendor/rbxutil/timer/init.luau +249 -0
  218. package/vendor/rbxutil/timer/init.test.luau +73 -0
  219. package/vendor/rbxutil/timer/wally.toml +11 -0
  220. package/vendor/rbxutil/tree/index.d.ts +15 -0
  221. package/vendor/rbxutil/tree/init.luau +137 -0
  222. package/vendor/rbxutil/tree/wally.toml +8 -0
  223. package/vendor/rbxutil/trove/index.d.ts +46 -0
  224. package/vendor/rbxutil/trove/init.luau +787 -0
  225. package/vendor/rbxutil/trove/init.test.luau +203 -0
  226. package/vendor/rbxutil/trove/wally.toml +8 -0
  227. package/vendor/rbxutil/typed-remote/init.luau +196 -0
  228. package/vendor/rbxutil/typed-remote/wally.toml +8 -0
  229. package/vendor/rbxutil/wait-for/index.d.ts +17 -0
  230. package/vendor/rbxutil/wait-for/init.luau +257 -0
  231. package/vendor/rbxutil/wait-for/init.test.luau +182 -0
  232. package/vendor/rbxutil/wait-for/wally.toml +11 -0
  233. package/vendor/t/t.lua +1350 -0
  234. package/vendor/testez/Context.lua +26 -0
  235. package/vendor/testez/Expectation.lua +311 -0
  236. package/vendor/testez/ExpectationContext.lua +38 -0
  237. package/vendor/testez/LifecycleHooks.lua +89 -0
  238. package/vendor/testez/Reporters/TeamCityReporter.lua +102 -0
  239. package/vendor/testez/Reporters/TextReporter.lua +106 -0
  240. package/vendor/testez/Reporters/TextReporterQuiet.lua +97 -0
  241. package/vendor/testez/TestBootstrap.lua +147 -0
  242. package/vendor/testez/TestEnum.lua +28 -0
  243. package/vendor/testez/TestPlan.lua +304 -0
  244. package/vendor/testez/TestPlanner.lua +40 -0
  245. package/vendor/testez/TestResults.lua +112 -0
  246. package/vendor/testez/TestRunner.lua +188 -0
  247. package/vendor/testez/TestSession.lua +243 -0
  248. package/vendor/testez/init.lua +40 -0
@@ -0,0 +1,295 @@
1
+ -- RemoteProperty
2
+ -- Stephen Leitnick
3
+ -- December 20, 2021
4
+
5
+ local Players = game:GetService("Players")
6
+
7
+ local RemoteSignal = require(script.Parent.RemoteSignal)
8
+ local Types = require(script.Parent.Parent.Types)
9
+ local Util = require(script.Parent.Parent.Util)
10
+
11
+ local None = Util.None
12
+
13
+ --[=[
14
+ @class RemoteProperty
15
+ @server
16
+ Created via `ServerComm:CreateProperty()`.
17
+
18
+ Values set can be anything that can pass through a
19
+ [RemoteEvent](https://developer.roblox.com/en-us/articles/Remote-Functions-and-Events#parameter-limitations).
20
+
21
+ Here is a cheat-sheet for the below methods:
22
+ - Setting data
23
+ - `Set`: Set "top" value for all current and future players. Overrides any custom-set data per player.
24
+ - `SetTop`: Set the "top" value for all players, but does _not_ override any custom-set data per player.
25
+ - `SetFor`: Set custom data for the given player. Overrides the "top" value. (_Can be nil_)
26
+ - `SetForList`: Same as `SetFor`, but accepts a list of players.
27
+ - `SetFilter`: Accepts a predicate function which checks for which players to set.
28
+ - Clearing data
29
+ - `ClearFor`: Clears the custom data set for a given player. Player will start using the "top" level value instead.
30
+ - `ClearForList`: Same as `ClearFor`, but accepts a list of players.
31
+ - `ClearFilter`: Accepts a predicate function which checks for which players to clear.
32
+ - Getting data
33
+ - `Get`: Retrieves the "top" value
34
+ - `GetFor`: Gets the current value for the given player. If cleared, returns the top value.
35
+
36
+ :::caution Network
37
+ Calling any of the data setter methods (e.g. `Set()`) will
38
+ fire the underlying RemoteEvent to replicate data to the
39
+ clients. Therefore, setting data should only occur when it
40
+ is necessary to change the data that the clients receive.
41
+ :::
42
+
43
+ :::caution Tables
44
+ Tables _can_ be used with RemoteProperties. However, the
45
+ RemoteProperty object will _not_ watch for changes within
46
+ the table. Therefore, anytime changes are made to the table,
47
+ the data must be set again using one of the setter methods.
48
+ :::
49
+ ]=]
50
+ local RemoteProperty = {}
51
+ RemoteProperty.__index = RemoteProperty
52
+
53
+ function RemoteProperty.new(
54
+ parent: Instance,
55
+ name: string,
56
+ initialValue: any,
57
+ inboundMiddleware: Types.ServerMiddleware?,
58
+ outboundMiddleware: Types.ServerMiddleware?
59
+ )
60
+ local self = setmetatable({}, RemoteProperty)
61
+ self._rs = RemoteSignal.new(parent, name, false, inboundMiddleware, outboundMiddleware)
62
+ self._value = initialValue
63
+ self._perPlayer = {}
64
+ self._playerRemoving = Players.PlayerRemoving:Connect(function(player)
65
+ self._perPlayer[player] = nil
66
+ end)
67
+ self._rs:Connect(function(player)
68
+ local playerValue = self._perPlayer[player]
69
+ local value = if playerValue == nil then self._value elseif playerValue == None then nil else playerValue
70
+ self._rs:Fire(player, value)
71
+ end)
72
+ return self
73
+ end
74
+
75
+ --[=[
76
+ Sets the top-level value of all clients to the same value.
77
+
78
+ :::note Override Per-Player Data
79
+ This will override any per-player data that was set using
80
+ `SetFor` or `SetFilter`. To avoid overriding this data,
81
+ `SetTop` can be used instead.
82
+ :::
83
+
84
+ ```lua
85
+ -- Examples
86
+ remoteProperty:Set(10)
87
+ remoteProperty:Set({SomeData = 32})
88
+ remoteProperty:Set("HelloWorld")
89
+ ```
90
+ ]=]
91
+ function RemoteProperty:Set(value: any)
92
+ self._value = value
93
+ table.clear(self._perPlayer)
94
+ self._rs:FireAll(value)
95
+ end
96
+
97
+ --[=[
98
+ Set the top-level value of the property, but does not override
99
+ any per-player data (e.g. set with `SetFor` or `SetFilter`).
100
+ Any player without custom-set data will receive this new data.
101
+
102
+ This is useful if certain players have specific values that
103
+ should not be changed, but all other players should receive
104
+ the same new value.
105
+
106
+ ```lua
107
+ -- Using just 'Set' overrides per-player data:
108
+ remoteProperty:SetFor(somePlayer, "CustomData")
109
+ remoteProperty:Set("Data")
110
+ print(remoteProperty:GetFor(somePlayer)) --> "Data"
111
+
112
+ -- Using 'SetTop' does not override:
113
+ remoteProperty:SetFor(somePlayer, "CustomData")
114
+ remoteProperty:SetTop("Data")
115
+ print(remoteProperty:GetFor(somePlayer)) --> "CustomData"
116
+ ```
117
+ ]=]
118
+ function RemoteProperty:SetTop(value: any)
119
+ self._value = value
120
+ for _, player in ipairs(Players:GetPlayers()) do
121
+ if self._perPlayer[player] == nil then
122
+ self._rs:Fire(player, value)
123
+ end
124
+ end
125
+ end
126
+
127
+ --[=[
128
+ @param value any -- Value to set for the clients (and to the predicate)
129
+ Sets the value for specific clients that pass the `predicate`
130
+ function test. This can be used to finely set the values
131
+ based on more control logic (e.g. setting certain values
132
+ per team).
133
+
134
+ ```lua
135
+ -- Set the value of "NewValue" to players with a name longer than 10 characters:
136
+ remoteProperty:SetFilter(function(player)
137
+ return #player.Name > 10
138
+ end, "NewValue")
139
+ ```
140
+ ]=]
141
+ function RemoteProperty:SetFilter(predicate: (Player, any) -> boolean, value: any)
142
+ for _, player in ipairs(Players:GetPlayers()) do
143
+ if predicate(player, value) then
144
+ self:SetFor(player, value)
145
+ end
146
+ end
147
+ end
148
+
149
+ --[=[
150
+ Set the value of the property for a specific player. This
151
+ will override the value used by `Set` (and the initial value
152
+ set for the property when created).
153
+
154
+ This value _can_ be `nil`. In order to reset the value for a
155
+ given player and let the player use the top-level value held
156
+ by this property, either use `Set` to set all players' data,
157
+ or use `ClearFor`.
158
+
159
+ ```lua
160
+ remoteProperty:SetFor(somePlayer, "CustomData")
161
+ ```
162
+ ]=]
163
+ function RemoteProperty:SetFor(player: Player, value: any)
164
+ if player.Parent then
165
+ self._perPlayer[player] = if value == nil then None else value
166
+ end
167
+ self._rs:Fire(player, value)
168
+ end
169
+
170
+ --[=[
171
+ Set the value of the property for specific players. This just
172
+ loops through the players given and calls `SetFor`.
173
+
174
+ ```lua
175
+ local players = {player1, player2, player3}
176
+ remoteProperty:SetForList(players, "CustomData")
177
+ ```
178
+ ]=]
179
+ function RemoteProperty:SetForList(players: { Player }, value: any)
180
+ for _, player in ipairs(players) do
181
+ self:SetFor(player, value)
182
+ end
183
+ end
184
+
185
+ --[=[
186
+ Clears the custom property value for the given player. When
187
+ this occurs, the player will reset to use the top-level
188
+ value held by this property (either the value set when the
189
+ property was created, or the last value set by `Set`).
190
+
191
+ ```lua
192
+ remoteProperty:Set("DATA")
193
+
194
+ remoteProperty:SetFor(somePlayer, "CUSTOM_DATA")
195
+ print(remoteProperty:GetFor(somePlayer)) --> "CUSTOM_DATA"
196
+
197
+ -- DOES NOT CLEAR, JUST SETS CUSTOM DATA TO NIL:
198
+ remoteProperty:SetFor(somePlayer, nil)
199
+ print(remoteProperty:GetFor(somePlayer)) --> nil
200
+
201
+ -- CLEAR:
202
+ remoteProperty:ClearFor(somePlayer)
203
+ print(remoteProperty:GetFor(somePlayer)) --> "DATA"
204
+ ```
205
+ ]=]
206
+ function RemoteProperty:ClearFor(player: Player)
207
+ if self._perPlayer[player] == nil then
208
+ return
209
+ end
210
+ self._perPlayer[player] = nil
211
+ self._rs:Fire(player, self._value)
212
+ end
213
+
214
+ --[=[
215
+ Clears the custom value for the given players. This
216
+ just loops through the list of players and calls
217
+ the `ClearFor` method for each player.
218
+ ]=]
219
+ function RemoteProperty:ClearForList(players: { Player })
220
+ for _, player in ipairs(players) do
221
+ self:ClearFor(player)
222
+ end
223
+ end
224
+
225
+ --[=[
226
+ The same as `SetFiler`, except clears the custom value
227
+ for any player that passes the predicate.
228
+ ]=]
229
+ function RemoteProperty:ClearFilter(predicate: (Player) -> boolean)
230
+ for _, player in ipairs(Players:GetPlayers()) do
231
+ if predicate(player) then
232
+ self:ClearFor(player)
233
+ end
234
+ end
235
+ end
236
+
237
+ --[=[
238
+ Returns the top-level value held by the property. This will
239
+ either be the initial value set, or the last value set
240
+ with `Set()`.
241
+
242
+ ```lua
243
+ remoteProperty:Set("Data")
244
+ print(remoteProperty:Get()) --> "Data"
245
+ ```
246
+ ]=]
247
+ function RemoteProperty:Get(): any
248
+ return self._value
249
+ end
250
+
251
+ --[=[
252
+ Returns the current value for the given player. This value
253
+ will depend on if `SetFor` or `SetFilter` has affected the
254
+ custom value for the player. If so, that custom value will
255
+ be returned. Otherwise, the top-level value will be used
256
+ (e.g. value from `Set`).
257
+
258
+ ```lua
259
+ -- Set top level data:
260
+ remoteProperty:Set("Data")
261
+ print(remoteProperty:GetFor(somePlayer)) --> "Data"
262
+
263
+ -- Set custom data:
264
+ remoteProperty:SetFor(somePlayer, "CustomData")
265
+ print(remoteProperty:GetFor(somePlayer)) --> "CustomData"
266
+
267
+ -- Set top level again, overriding custom data:
268
+ remoteProperty:Set("NewData")
269
+ print(remoteProperty:GetFor(somePlayer)) --> "NewData"
270
+
271
+ -- Set custom data again, and set top level without overriding:
272
+ remoteProperty:SetFor(somePlayer, "CustomData")
273
+ remoteProperty:SetTop("Data")
274
+ print(remoteProperty:GetFor(somePlayer)) --> "CustomData"
275
+
276
+ -- Clear custom data to use top level data:
277
+ remoteProperty:ClearFor(somePlayer)
278
+ print(remoteProperty:GetFor(somePlayer)) --> "Data"
279
+ ```
280
+ ]=]
281
+ function RemoteProperty:GetFor(player: Player): any
282
+ local playerValue = self._perPlayer[player]
283
+ local value = if playerValue == nil then self._value elseif playerValue == None then nil else playerValue
284
+ return value
285
+ end
286
+
287
+ --[=[
288
+ Destroys the RemoteProperty object.
289
+ ]=]
290
+ function RemoteProperty:Destroy()
291
+ self._rs:Destroy()
292
+ self._playerRemoving:Disconnect()
293
+ end
294
+
295
+ return RemoteProperty
@@ -0,0 +1,211 @@
1
+ -- RemoteSignal
2
+ -- Stephen Leitnick
3
+ -- December 20, 2021
4
+
5
+ local Players = game:GetService("Players")
6
+
7
+ local Signal = require(script.Parent.Parent.Parent.Signal)
8
+ local Types = require(script.Parent.Parent.Types)
9
+
10
+ --[=[
11
+ @class RemoteSignal
12
+ @server
13
+ Created via `ServerComm:CreateSignal()`.
14
+ ]=]
15
+ local RemoteSignal = {}
16
+ RemoteSignal.__index = RemoteSignal
17
+
18
+ --[=[
19
+ @within RemoteSignal
20
+ @interface Connection
21
+ .Disconnect () -> nil
22
+ .Connected boolean
23
+
24
+ Represents a connection.
25
+ ]=]
26
+
27
+ function RemoteSignal.new(
28
+ parent: Instance,
29
+ name: string,
30
+ unreliable: boolean?,
31
+ inboundMiddleware: Types.ServerMiddleware?,
32
+ outboundMiddleware: Types.ServerMiddleware?
33
+ )
34
+ local self = setmetatable({}, RemoteSignal)
35
+ self._re = if unreliable == true then Instance.new("UnreliableRemoteEvent") else Instance.new("RemoteEvent")
36
+ self._re.Name = name
37
+ self._re.Parent = parent
38
+ if outboundMiddleware and #outboundMiddleware > 0 then
39
+ self._hasOutbound = true
40
+ self._outbound = outboundMiddleware
41
+ else
42
+ self._hasOutbound = false
43
+ end
44
+ if inboundMiddleware and #inboundMiddleware > 0 then
45
+ self._directConnect = false
46
+ self._signal = Signal.new()
47
+ self._re.OnServerEvent:Connect(function(player, ...)
48
+ local args = table.pack(...)
49
+ for _, middlewareFunc in inboundMiddleware do
50
+ local middlewareResult = table.pack(middlewareFunc(player, args))
51
+ if not middlewareResult[1] then
52
+ return
53
+ end
54
+ args.n = #args
55
+ end
56
+ self._signal:Fire(player, table.unpack(args, 1, args.n))
57
+ end)
58
+ else
59
+ self._directConnect = true
60
+ end
61
+ return self
62
+ end
63
+
64
+ --[=[
65
+ @return boolean
66
+ Returns `true` if the underlying RemoteSignal is bound to an
67
+ UnreliableRemoteEvent object.
68
+ ]=]
69
+ function RemoteSignal:IsUnreliable(): boolean
70
+ return self._re:IsA("UnreliableRemoteEvent")
71
+ end
72
+
73
+ --[=[
74
+ @param fn (player: Player, ...: any) -> nil -- The function to connect
75
+ @return Connection
76
+ Connect a function to the signal. Anytime a matching ClientRemoteSignal
77
+ on a client fires, the connected function will be invoked with the
78
+ arguments passed by the client.
79
+ ]=]
80
+ function RemoteSignal:Connect(fn)
81
+ if self._directConnect then
82
+ return self._re.OnServerEvent:Connect(fn)
83
+ else
84
+ return self._signal:Connect(fn)
85
+ end
86
+ end
87
+
88
+ function RemoteSignal:_processOutboundMiddleware(player: Player?, ...: any)
89
+ if not self._hasOutbound then
90
+ return ...
91
+ end
92
+ local args = table.pack(...)
93
+ for _, middlewareFunc in self._outbound do
94
+ local middlewareResult = table.pack(middlewareFunc(player, args))
95
+ if not middlewareResult[1] then
96
+ return table.unpack(middlewareResult, 2, middlewareResult.n)
97
+ end
98
+ args.n = #args
99
+ end
100
+ return table.unpack(args, 1, args.n)
101
+ end
102
+
103
+ --[=[
104
+ @param player Player -- The target client
105
+ @param ... any -- Arguments passed to the client
106
+ Fires the signal at the specified client with any arguments.
107
+
108
+ :::note Outbound Middleware
109
+ All arguments pass through any outbound middleware (if any)
110
+ before being sent to the clients.
111
+ :::
112
+ ]=]
113
+ function RemoteSignal:Fire(player: Player, ...: any)
114
+ self._re:FireClient(player, self:_processOutboundMiddleware(player, ...))
115
+ end
116
+
117
+ --[=[
118
+ @param ... any
119
+ Fires the signal at _all_ clients with any arguments.
120
+
121
+ :::note Outbound Middleware
122
+ All arguments pass through any outbound middleware (if any)
123
+ before being sent to the clients.
124
+ :::
125
+ ]=]
126
+ function RemoteSignal:FireAll(...: any)
127
+ self._re:FireAllClients(self:_processOutboundMiddleware(nil, ...))
128
+ end
129
+
130
+ --[=[
131
+ @param ignorePlayer Player -- The client to ignore
132
+ @param ... any -- Arguments passed to the other clients
133
+ Fires the signal to all clients _except_ the specified
134
+ client.
135
+
136
+ :::note Outbound Middleware
137
+ All arguments pass through any outbound middleware (if any)
138
+ before being sent to the clients.
139
+ :::
140
+ ]=]
141
+ function RemoteSignal:FireExcept(ignorePlayer: Player, ...: any)
142
+ self:FireFilter(function(plr)
143
+ return plr ~= ignorePlayer
144
+ end, ...)
145
+ end
146
+
147
+ --[=[
148
+ @param predicate (player: Player, argsFromFire: ...) -> boolean
149
+ @param ... any -- Arguments to pass to the clients (and to the predicate)
150
+ Fires the signal at any clients that pass the `predicate`
151
+ function test. This can be used to fire signals with much
152
+ more control logic.
153
+
154
+ :::note Outbound Middleware
155
+ All arguments pass through any outbound middleware (if any)
156
+ before being sent to the clients.
157
+ :::
158
+
159
+ :::caution Predicate Before Middleware
160
+ The arguments sent to the predicate are sent _before_ getting
161
+ transformed by any middleware.
162
+ :::
163
+
164
+ ```lua
165
+ -- Fire signal to players of the same team:
166
+ remoteSignal:FireFilter(function(player)
167
+ return player.Team.Name == "Best Team"
168
+ end)
169
+ ```
170
+ ]=]
171
+ function RemoteSignal:FireFilter(predicate: (Player, ...any) -> boolean, ...: any)
172
+ for _, player in Players:GetPlayers() do
173
+ if predicate(player, ...) then
174
+ self._re:FireClient(player, self:_processOutboundMiddleware(nil, ...))
175
+ end
176
+ end
177
+ end
178
+
179
+ --[=[
180
+ Fires a signal at the clients within the `players` table. This is
181
+ useful when signals need to fire for a specific set of players.
182
+
183
+ For more complex firing, see `FireFilter`.
184
+
185
+ :::note Outbound Middleware
186
+ All arguments pass through any outbound middleware (if any)
187
+ before being sent to the clients.
188
+ :::
189
+
190
+ ```lua
191
+ local players = {somePlayer1, somePlayer2, somePlayer3}
192
+ remoteSignal:FireFor(players, "Hello, players!")
193
+ ```
194
+ ]=]
195
+ function RemoteSignal:FireFor(players: { Player }, ...: any)
196
+ for _, player in players do
197
+ self._re:FireClient(player, self:_processOutboundMiddleware(nil, ...))
198
+ end
199
+ end
200
+
201
+ --[=[
202
+ Destroys the RemoteSignal object.
203
+ ]=]
204
+ function RemoteSignal:Destroy()
205
+ self._re:Destroy()
206
+ if self._signal then
207
+ self._signal:Destroy()
208
+ end
209
+ end
210
+
211
+ return RemoteSignal
@@ -0,0 +1,211 @@
1
+ -- ServerComm
2
+ -- Stephen Leitnick
3
+ -- December 20, 2021
4
+
5
+ local Comm = require(script.Parent)
6
+ local Types = require(script.Parent.Parent.Types)
7
+ local Util = require(script.Parent.Parent.Util)
8
+
9
+ --[=[
10
+ @class ServerComm
11
+ @server
12
+ ]=]
13
+ local ServerComm = {}
14
+ ServerComm.__index = ServerComm
15
+
16
+ --[=[
17
+ @within ServerComm
18
+ @type ServerMiddlewareFn (player: Player, args: {any}) -> (shouldContinue: boolean, ...: any)
19
+ The middleware function takes the client player and the arguments (as a table array), and should
20
+ return `true|false` to indicate if the process should continue.
21
+
22
+ If returning `false`, the optional varargs after the `false` are used as the new return values
23
+ to whatever was calling the middleware.
24
+ ]=]
25
+ --[=[
26
+ @within ServerComm
27
+ @type ServerMiddleware {ServerMiddlewareFn}
28
+ Array of middleware functions.
29
+ ]=]
30
+
31
+ --[=[
32
+ @return ServerComm
33
+ Constructs a ServerComm object. The `namespace` parameter is used
34
+ in cases where more than one ServerComm object may be bound
35
+ to the same object. Otherwise, a default namespace is used.
36
+
37
+ ```lua
38
+ local serverComm = ServerComm.new(game:GetService("ReplicatedStorage"))
39
+
40
+ -- If many might exist in the given parent, use a unique namespace:
41
+ local serverComm = ServerComm.new(game:GetService("ReplicatedStorage"), "MyNamespace")
42
+ ```
43
+ ]=]
44
+ function ServerComm.new(parent: Instance, namespace: string?)
45
+ assert(Util.IsServer, "ServerComm must be constructed from the server")
46
+ assert(typeof(parent) == "Instance", "Parent must be of type Instance")
47
+ local ns = Util.DefaultCommFolderName
48
+ if namespace then
49
+ ns = namespace
50
+ end
51
+ assert(not parent:FindFirstChild(ns), "Parent already has another ServerComm bound to namespace " .. ns)
52
+ local self = setmetatable({}, ServerComm)
53
+ self._instancesFolder = Instance.new("Folder")
54
+ self._instancesFolder.Name = ns
55
+ self._instancesFolder.Parent = parent
56
+ return self
57
+ end
58
+
59
+ --[=[
60
+ @param name string
61
+ @param fn (player: Player, ...: any) -> ...: any
62
+ @param inboundMiddleware ServerMiddleware?
63
+ @param outboundMiddleware ServerMiddleware?
64
+ @return RemoteFunction
65
+ Creates a RemoteFunction and binds the given function to it. Inbound
66
+ and outbound middleware can be applied if desired.
67
+
68
+ ```lua
69
+ local function GetSomething(player: Player)
70
+ return "Something"
71
+ end
72
+
73
+ serverComm:BindFunction("GetSomething", GetSomething)
74
+ ```
75
+ ]=]
76
+ function ServerComm:BindFunction(
77
+ name: string,
78
+ fn: Types.FnBind,
79
+ inboundMiddleware: Types.ServerMiddleware?,
80
+ outboundMiddleware: Types.ServerMiddleware?
81
+ ): RemoteFunction
82
+ return Comm.BindFunction(self._instancesFolder, name, fn, inboundMiddleware, outboundMiddleware)
83
+ end
84
+
85
+ --[=[
86
+ @param tbl table
87
+ @param name string
88
+ @param inboundMiddleware ServerMiddleware?
89
+ @param outboundMiddleware ServerMiddleware?
90
+ @return RemoteFunction
91
+
92
+ Binds a function to a table method. The name must match the
93
+ name of the method in the table. The same name will be used
94
+ on the client to access the given function.
95
+
96
+ ```lua
97
+ local MyObject = {
98
+ _Data = 10,
99
+ }
100
+
101
+ function MyObject:GetData(player: Player)
102
+ return self._Data
103
+ end
104
+
105
+ serverComm:WrapMethod(MyObject, "GetData")
106
+ ```
107
+ ]=]
108
+ function ServerComm:WrapMethod(
109
+ tbl: {},
110
+ name: string,
111
+ inboundMiddleware: Types.ServerMiddleware?,
112
+ outboundMiddleware: Types.ServerMiddleware?
113
+ ): RemoteFunction
114
+ return Comm.WrapMethod(self._instancesFolder, tbl, name, inboundMiddleware, outboundMiddleware)
115
+ end
116
+
117
+ --[=[
118
+ @param name string
119
+ @param unreliable boolean?
120
+ @param inboundMiddleware ServerMiddleware?
121
+ @param outboundMiddleware ServerMiddleware?
122
+ @return RemoteSignal
123
+
124
+ Creates a signal that can be used to fire data to the clients
125
+ or receive data from the clients.
126
+
127
+ By default, signals use RemoteEvents internally. However, if
128
+ the `unreliable` argument is set to `true`, then an
129
+ UnreliableRemoteEvent will be used instead.
130
+
131
+ ```lua
132
+ local mySignal = serverComm:CreateSignal("MySignal")
133
+
134
+ -- Examples of firing in different ways (see docs for RemoteSignal for further info):
135
+ mySignal:Fire(somePlayer, "Hello world")
136
+ mySignal:FireAll("Hi there")
137
+ mySignal:FireExcept(somePlayer, "Hello everyone except " .. somePlayer.Name)
138
+ mySignal:FireFilter(function(player) return player.Team == someCoolTeam end, "Hello cool team")
139
+
140
+ -- Example of listening for clients to send data:
141
+ mySignal:Connect(function(player, message)
142
+ print("Got a message from " .. player.Name .. ":", message)
143
+ end)
144
+ ```
145
+ ]=]
146
+ function ServerComm:CreateSignal(
147
+ name: string,
148
+ unreliable: boolean?,
149
+ inboundMiddleware: Types.ServerMiddleware?,
150
+ outboundMiddleware: Types.ServerMiddleware?
151
+ )
152
+ return Comm.CreateSignal(self._instancesFolder, name, unreliable, inboundMiddleware, outboundMiddleware)
153
+ end
154
+
155
+ --[=[
156
+ @param name string
157
+ @param initialValue any
158
+ @param inboundMiddleware ServerMiddleware?
159
+ @param outboundMiddleware ServerMiddleware?
160
+ @return RemoteProperty
161
+
162
+ Create a property object which will replicate its property value to
163
+ the clients. Optionally, specific clients can be targeted with
164
+ different property values.
165
+
166
+ ```lua
167
+ local comm = Comm.ServerComm.new(game:GetService("ReplicatedStorage"))
168
+
169
+ local mapInfo = comm:CreateProperty("MapInfo", {
170
+ MapName = "TheAwesomeMap",
171
+ MapDuration = 60,
172
+ })
173
+
174
+ -- Change the data:
175
+ mapInfo:Set({
176
+ MapName = "AnotherMap",
177
+ MapDuration = 30,
178
+ })
179
+
180
+ -- Change the data for one player:
181
+ mapInfo:SetFor(somePlayer, {
182
+ MapName = "ASpecialMapForYou",
183
+ MapDuration = 90,
184
+ })
185
+
186
+ -- Change data based on a predicate function:
187
+ mapInfo:SetFilter(function(player)
188
+ return player.Team == game.Teams.SomeSpecialTeam
189
+ end, {
190
+ MapName = "TeamMap",
191
+ MapDuration = 20,
192
+ })
193
+ ```
194
+ ]=]
195
+ function ServerComm:CreateProperty(
196
+ name: string,
197
+ initialValue: any,
198
+ inboundMiddleware: Types.ServerMiddleware?,
199
+ outboundMiddleware: Types.ServerMiddleware?
200
+ )
201
+ return Comm.CreateProperty(self._instancesFolder, name, initialValue, inboundMiddleware, outboundMiddleware)
202
+ end
203
+
204
+ --[=[
205
+ Destroy the ServerComm object.
206
+ ]=]
207
+ function ServerComm:Destroy()
208
+ self._instancesFolder:Destroy()
209
+ end
210
+
211
+ return ServerComm