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,249 @@
1
+ --!strict
2
+
3
+ local RunService = game:GetService("RunService")
4
+
5
+ local Signal = require(script.Parent.Signal)
6
+
7
+ --[=[
8
+ @within Timer
9
+ @type CallbackFn () -> ()
10
+ Callback function.
11
+ ]=]
12
+ type CallbackFn = () -> nil
13
+
14
+ --[=[
15
+ @within Timer
16
+ @type TimeFn () -> number
17
+ Time function.
18
+ ]=]
19
+ type TimeFn = () -> number
20
+
21
+ --[=[
22
+ @class Timer
23
+
24
+ The Timer class allows for code to run periodically at specified intervals.
25
+
26
+ ```lua
27
+ local timer = Timer.new(2)
28
+ timer.Tick:Connect(function()
29
+ print("Tock")
30
+ end)
31
+ timer:Start()
32
+ ```
33
+ ]=]
34
+ local Timer = {}
35
+ Timer.__index = Timer
36
+
37
+ export type Timer = typeof(setmetatable(
38
+ {} :: {
39
+ Interval: number,
40
+ UpdateSignal: RBXScriptSignal,
41
+ TimeFunction: () -> number,
42
+ AllowDrift: boolean,
43
+ Tick: Signal.Signal<>,
44
+
45
+ _runHandle: RBXScriptConnection?,
46
+ },
47
+ Timer
48
+ ))
49
+
50
+ --[=[
51
+ @within Timer
52
+ @prop Interval number
53
+ Interval at which the `Tick` event fires.
54
+ ]=]
55
+ --[=[
56
+ @within Timer
57
+ @prop UpdateSignal RBXScriptSignal | Signal
58
+ The signal which updates the timer internally.
59
+ ]=]
60
+ --[=[
61
+ @within Timer
62
+ @prop TimeFunction TimeFn
63
+ The function which gets the current time.
64
+ ]=]
65
+ --[=[
66
+ @within Timer
67
+ @prop AllowDrift boolean
68
+ Flag which indicates if the timer is allowed to drift. This
69
+ is set to `true` by default. This flag must be set before
70
+ calling `Start` or `StartNow`. This flag should only be set
71
+ to `false` if it is necessary for drift to be eliminated.
72
+ ]=]
73
+ --[=[
74
+ @within Timer
75
+ @prop Tick RBXScriptSignal | Signal
76
+ The event which is fired every time the timer hits its interval.
77
+ ]=]
78
+
79
+ --[=[
80
+ @return Timer
81
+
82
+ Creates a new timer.
83
+ ]=]
84
+ function Timer.new(interval: number): Timer
85
+ assert(type(interval) == "number", "argument #1 to Timer.new must be a number; got " .. type(interval))
86
+ assert(interval >= 0, "argument #1 to Timer.new must be greater or equal to 0; got " .. tostring(interval))
87
+
88
+ local self = setmetatable({}, Timer)
89
+
90
+ self._runHandle = nil
91
+ self.Interval = interval
92
+ self.UpdateSignal = RunService.Heartbeat
93
+ self.TimeFunction = time
94
+ self.AllowDrift = true
95
+ self.Tick = Signal.new()
96
+
97
+ return self
98
+ end
99
+
100
+ --[=[
101
+ @return RBXScriptConnection
102
+
103
+ Creates a simplified timer which just fires off a callback function at the given interval.
104
+
105
+ ```lua
106
+ -- Basic:
107
+ Timer.simple(1, function()
108
+ print("Tick")
109
+ end)
110
+
111
+ -- Using other arguments:
112
+ Timer.simple(1, function()
113
+ print("Tick")
114
+ end, true, RunService.Heartbeat, os.clock)
115
+ ```
116
+ ]=]
117
+ function Timer.simple(
118
+ interval: number,
119
+ callback: CallbackFn,
120
+ startNow: boolean?,
121
+ updateSignal: RBXScriptSignal?,
122
+ timeFn: TimeFn?
123
+ )
124
+ local update = updateSignal or RunService.Heartbeat
125
+ local t = timeFn or time
126
+ local nextTick = t() + interval
127
+
128
+ if startNow then
129
+ task.defer(callback)
130
+ end
131
+
132
+ return update:Connect(function()
133
+ local now = t()
134
+ if now >= nextTick then
135
+ nextTick = now + interval
136
+ task.defer(callback)
137
+ end
138
+ end)
139
+ end
140
+
141
+ --[=[
142
+ Returns `true` if the given object is a Timer.
143
+ ]=]
144
+ function Timer.is(obj: any): boolean
145
+ return type(obj) == "table" and getmetatable(obj) == Timer
146
+ end
147
+
148
+ function Timer._startTimer(self: Timer)
149
+ local t = self.TimeFunction
150
+ local nextTick = t() + self.Interval
151
+
152
+ self._runHandle = self.UpdateSignal:Connect(function()
153
+ local now = t()
154
+ if now >= nextTick then
155
+ nextTick = now + self.Interval
156
+ self.Tick:Fire()
157
+ end
158
+ end)
159
+ end
160
+
161
+ function Timer._startTimerNoDrift(self: Timer)
162
+ assert(self.Interval > 0, "interval must be greater than 0 when AllowDrift is set to false")
163
+
164
+ local t = self.TimeFunction
165
+ local n = 1
166
+ local start = t()
167
+ local nextTick = start + self.Interval
168
+ self._runHandle = self.UpdateSignal:Connect(function()
169
+ local now = t()
170
+ while now >= nextTick do
171
+ n += 1
172
+ nextTick = start + (self.Interval * n)
173
+ self.Tick:Fire()
174
+ end
175
+ end)
176
+ end
177
+
178
+ --[=[
179
+ Starts the timer. Will do nothing if the timer is already running.
180
+
181
+ ```lua
182
+ timer:Start()
183
+ ```
184
+ ]=]
185
+ function Timer.Start(self: Timer)
186
+ if self._runHandle then
187
+ return
188
+ end
189
+ if self.AllowDrift then
190
+ self:_startTimer()
191
+ else
192
+ self:_startTimerNoDrift()
193
+ end
194
+ end
195
+
196
+ --[=[
197
+ Starts the timer and fires off the Tick event immediately. Will do
198
+ nothing if the timer is already running.
199
+
200
+ ```lua
201
+ timer:StartNow()
202
+ ```
203
+ ]=]
204
+ function Timer.StartNow(self: Timer)
205
+ if self._runHandle then
206
+ return
207
+ end
208
+ self.Tick:Fire()
209
+ self:Start()
210
+ end
211
+
212
+ --[=[
213
+ Stops the timer. Will do nothing if the timer is already stopped.
214
+
215
+ ```lua
216
+ timer:Stop()
217
+ ```
218
+ ]=]
219
+ function Timer.Stop(self: Timer)
220
+ if not self._runHandle then
221
+ return
222
+ end
223
+
224
+ self._runHandle:Disconnect()
225
+ self._runHandle = nil
226
+ end
227
+
228
+ --[=[
229
+ Returns `true` if the timer is currently running.
230
+
231
+ ```lua
232
+ if timer:IsRunning() then
233
+ -- Do something
234
+ end
235
+ ```
236
+ ]=]
237
+ function Timer.IsRunning(self: Timer): boolean
238
+ return self._runHandle ~= nil
239
+ end
240
+
241
+ --[=[
242
+ Destroys the timer. This will also stop the timer.
243
+ ]=]
244
+ function Timer.Destroy(self: Timer)
245
+ self.Tick:Destroy()
246
+ self:Stop()
247
+ end
248
+
249
+ return Timer
@@ -0,0 +1,73 @@
1
+ local ServerScriptService = game:GetService("ServerScriptService")
2
+
3
+ local Test = require(ServerScriptService.TestRunner.Test)
4
+
5
+ return function(ctx: Test.TestContext)
6
+ local Timer = require(script.Parent)
7
+
8
+ ctx:Describe("Timer", function()
9
+ local timer
10
+
11
+ ctx:BeforeEach(function()
12
+ timer = Timer.new(0.1)
13
+ timer.TimeFunction = os.clock
14
+ end)
15
+
16
+ ctx:AfterEach(function()
17
+ if timer then
18
+ timer:Destroy()
19
+ timer = nil
20
+ end
21
+ end)
22
+
23
+ ctx:Test("should create a new timer", function()
24
+ ctx:Expect(Timer.is(timer)):ToBe(true)
25
+ end)
26
+
27
+ ctx:Test("should tick appropriately", function()
28
+ local start = os.clock()
29
+ timer:Start()
30
+ timer.Tick:Wait()
31
+ local duration = (os.clock() - start)
32
+ ctx:Expect(duration):ToBeNear(duration, 0.02)
33
+ end)
34
+
35
+ ctx:Test("should start immediately", function()
36
+ local start = os.clock()
37
+ local stop = nil
38
+ timer.Tick:Connect(function()
39
+ if not stop then
40
+ stop = os.clock()
41
+ end
42
+ end)
43
+ timer:StartNow()
44
+ timer.Tick:Wait()
45
+ ctx:Expect(stop):ToBeA("number")
46
+ local duration = (stop - start)
47
+ ctx:Expect(duration):ToBeNear(0, 0.02)
48
+ end)
49
+
50
+ ctx:Test("should stop", function()
51
+ local ticks = 0
52
+ timer.Tick:Connect(function()
53
+ ticks += 1
54
+ end)
55
+ timer:StartNow()
56
+ timer:Stop()
57
+ task.wait(1)
58
+ ctx:Expect(ticks):ToBe(1)
59
+ end)
60
+
61
+ ctx:Test("should detect if running", function()
62
+ ctx:Expect(timer:IsRunning()):ToBe(false)
63
+ timer:Start()
64
+ ctx:Expect(timer:IsRunning()):ToBe(true)
65
+ timer:Stop()
66
+ ctx:Expect(timer:IsRunning()):ToBe(false)
67
+ timer:StartNow()
68
+ ctx:Expect(timer:IsRunning()):ToBe(true)
69
+ timer:Stop()
70
+ ctx:Expect(timer:IsRunning()):ToBe(false)
71
+ end)
72
+ end)
73
+ end
@@ -0,0 +1,11 @@
1
+ [package]
2
+ name = "sleitnick/timer"
3
+ description = "Timer class"
4
+ version = "2.0.0"
5
+ license = "MIT"
6
+ authors = ["Stephen Leitnick"]
7
+ registry = "https://github.com/UpliftGames/wally-index"
8
+ realm = "shared"
9
+
10
+ [dependencies]
11
+ Signal = "sleitnick/signal@^2"
@@ -0,0 +1,15 @@
1
+ declare namespace Tree {
2
+ interface Constructor {
3
+ Find(parent: Instance, path: string): Instance;
4
+ Find<T extends keyof Instances>(parent: Instance, path: string, assertIsA: T): Instances[T];
5
+
6
+ Await(parent: Instance, path: string, timeout?: number): Instance;
7
+ Await<T extends keyof Instances>(parent: Instance, path: string, timeout: number, assertIsA: T): Instances[T];
8
+
9
+ Exists(parent: Instance, path: string, assertIsA?: keyof Instances): boolean;
10
+ }
11
+ }
12
+
13
+ declare const Tree: Tree.Constructor;
14
+
15
+ export = Tree;
@@ -0,0 +1,137 @@
1
+ local DELIM = "/"
2
+
3
+ local function FullNameToPath(instance: Instance): string
4
+ return instance:GetFullName():gsub("%.", DELIM)
5
+ end
6
+
7
+ --[=[
8
+ @class Tree
9
+ ]=]
10
+ local Tree = {}
11
+
12
+ --[=[
13
+ Similar to FindFirstChild, with a few key differences:
14
+ - An error is thrown if the instance is not found
15
+ - A path to the instance can be provided, delimited by forward slashes (e.g. `Path/To/Child`)
16
+ - Optionally, the instance's type can be asserted using `IsA`
17
+
18
+ ```lua
19
+ -- Find "Child" directly under parent:
20
+ local instance = Tree.Find(parent, "Child")
21
+
22
+ -- Find "Child" descendant:
23
+ local instance = Tree.Find(parent, "Path/To/Child")
24
+
25
+ -- Find "Child" descendant and assert that it's a BasePart:
26
+ local instance = Tree.Find(parent, "Path/To/Child", "BasePart") :: BasePart
27
+ ```
28
+ ]=]
29
+ function Tree.Find(parent: Instance, path: string, assertIsA: string?): Instance
30
+ local instance = parent
31
+ local paths = path:split(DELIM)
32
+
33
+ for _, p in paths do
34
+ -- Error for empty path parts:
35
+ if p == "" then
36
+ error(`Invalid path: {path}`, 2)
37
+ end
38
+
39
+ instance = instance:FindFirstChild(p)
40
+
41
+ -- Error if instance is not found:
42
+ if instance == nil then
43
+ error(`Failed to find {path} in {FullNameToPath(parent)}`, 2)
44
+ end
45
+ end
46
+
47
+ -- Assert class type if argument is supplied:
48
+ if assertIsA and not instance:IsA(assertIsA) then
49
+ error(`Got class {instance.ClassName}; expected to be of type {assertIsA}`, 2)
50
+ end
51
+
52
+ return instance
53
+ end
54
+
55
+ --[=[
56
+ Returns `true` if the instance is found. Similar to `Tree.Find`, except this returns `true|false`. No error is thrown unless the path is invalid.
57
+
58
+ ```lua
59
+ -- Check if "Child" exists directly in `parent`:
60
+ if Tree.Exists(parent, "Child") then ... end
61
+
62
+ -- Check if "Child" descendant exists at `parent.Path.To.Child`:
63
+ if Tree.Exists(parent, "Path/To/Child") then ... end
64
+
65
+ -- Check if "Child" descendant exists at `parent.Path.To.Child` and is a BasePart:
66
+ if Tree.Exists(parent, "Path/To/Child", "BasePart") then ... end
67
+ ```
68
+ ]=]
69
+ function Tree.Exists(parent: Instance, path: string, assertIsA: string?): boolean
70
+ local instance = parent
71
+ local paths = path:split(DELIM)
72
+
73
+ for _, p in paths do
74
+ -- Error for empty path parts:
75
+ if p == "" then
76
+ error(`Invalid path: {path}`, 2)
77
+ end
78
+
79
+ instance = instance:FindFirstChild(p)
80
+
81
+ if instance == nil then
82
+ return false
83
+ end
84
+ end
85
+
86
+ if assertIsA and not instance:IsA(assertIsA) then
87
+ return false
88
+ end
89
+
90
+ return true
91
+ end
92
+
93
+ --[=[
94
+ @yields
95
+ Waits for the path to exist within the parent instance. Similar to `Tree.Find`, except `WaitForChild`
96
+ is used internally. An optional `timeout` can be supplied, which is passed along to each call to
97
+ `WaitForChild`.
98
+
99
+ An error is thrown if the path fails to resolve. This will only happen if the path is invalid _or_ if
100
+ the supplied timeout is reached.
101
+
102
+ :::caution Indefinite Yield Possible
103
+ If the `timeout` parameter is not supplied, then the internal call to `WaitForChild` will yield
104
+ indefinitely until the child is found. It is good practice to supply a timeout parameter.
105
+ :::
106
+
107
+ ```lua
108
+ local child = Tree.Await(parent, "Path/To/Child", 30)
109
+ ```
110
+ ]=]
111
+ function Tree.Await(parent: Instance, path: string, timeout: number?, assertIsA: string?): Instance
112
+ local instance = parent
113
+ local paths = path:split(DELIM)
114
+
115
+ for _, p in paths do
116
+ -- Error for empty path parts:
117
+ if p == "" then
118
+ error(`Invalid path: {path}`, 2)
119
+ end
120
+
121
+ instance = instance:WaitForChild(p, timeout)
122
+
123
+ -- Error if instance is not found:
124
+ if instance == nil then
125
+ error(`Failed to await {path} in {FullNameToPath(parent)} (timeout reached)`, 2)
126
+ end
127
+ end
128
+
129
+ -- Assert class type if argument is supplied:
130
+ if assertIsA and not instance:IsA(assertIsA) then
131
+ error(`Got class {instance.ClassName}; expected to be of type {assertIsA}`, 2)
132
+ end
133
+
134
+ return instance
135
+ end
136
+
137
+ return Tree
@@ -0,0 +1,8 @@
1
+ [package]
2
+ name = "sleitnick/tree"
3
+ description = "Utility functions for accessing instances in the game hierarchy"
4
+ version = "1.1.0"
5
+ license = "MIT"
6
+ authors = ["Stephen Leitnick"]
7
+ registry = "https://github.com/UpliftGames/wally-index"
8
+ realm = "shared"
@@ -0,0 +1,46 @@
1
+ interface ConnectionLike {
2
+ Disconnect(this: ConnectionLike): void;
3
+ }
4
+
5
+ type Trackable =
6
+ | Instance
7
+ | RBXScriptConnection
8
+ | ConnectionLike
9
+ | Promise<unknown>
10
+ | thread
11
+ | ((...args: unknown[]) => unknown)
12
+ | { destroy: () => void }
13
+ | { disconnect: () => void }
14
+ | { Destroy: () => void }
15
+ | { Disconnect: () => void };
16
+
17
+ declare namespace Trove {
18
+ interface Constructor {
19
+ new (): Trove;
20
+ }
21
+ }
22
+
23
+ interface Trove {
24
+ Extend(): Trove;
25
+ Clone<T extends Instance>(): T;
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ Construct<T extends { new (...args: any[]): InstanceType<T> }>(
28
+ cls: T,
29
+ ...args: ConstructorParameters<T>
30
+ ): InstanceType<T>;
31
+ Connect<T extends Callback = Callback>(signal: RBXScriptSignal<T>, fn: T): RBXScriptConnection;
32
+ Once<T extends Callback = Callback>(signal: RBXScriptSignal<T>, fn: T): RBXScriptConnection;
33
+ BindToRenderStep(name: string, priority: number, fn: (dt: number) => void): void;
34
+ AddPromise<T>(promise: Promise<T>): Promise<T>;
35
+ Add<T extends Trackable>(object: T, cleanupMethod?: string): T;
36
+ Remove<T extends Trackable>(object: T): boolean;
37
+ Pop<T extends Trackable>(object: T): boolean;
38
+ AttachToInstance(instance: Instance): RBXScriptConnection;
39
+ Clean(): void;
40
+ WrapClean(): () => void;
41
+ Destroy(): void;
42
+ }
43
+
44
+ declare const Trove: Trove.Constructor;
45
+
46
+ export = Trove;