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.
- package/README.md +122 -0
- package/commands/setup-game.md +108 -0
- package/commands/sync-check.md +53 -0
- package/core/roblox-core.md +93 -0
- package/dist/server.js +167 -0
- package/package.json +35 -0
- package/skills/roblox-analytics/SKILL.md +277 -0
- package/skills/roblox-analytics/references/event-batcher.luau +75 -0
- package/skills/roblox-animation-vfx/SKILL.md +1325 -0
- package/skills/roblox-architecture/SKILL.md +863 -0
- package/skills/roblox-architecture/references/combat-systems.md +1381 -0
- package/skills/roblox-code-review/SKILL.md +687 -0
- package/skills/roblox-data/SKILL.md +889 -0
- package/skills/roblox-data/references/inventory-systems.md +1729 -0
- package/skills/roblox-debug/SKILL.md +99 -0
- package/skills/roblox-gui/SKILL.md +1103 -0
- package/skills/roblox-gui-fusion/SKILL.md +150 -0
- package/skills/roblox-gui-fusion/references/inventory.luau +427 -0
- package/skills/roblox-gui-fusion/references/settings-menu.luau +579 -0
- package/skills/roblox-gui-fusion/references/shop.luau +411 -0
- package/skills/roblox-luau-mastery/SKILL.md +1519 -0
- package/skills/roblox-monetization/SKILL.md +1084 -0
- package/skills/roblox-monetization/references/process-receipt.luau +131 -0
- package/skills/roblox-networking/SKILL.md +669 -0
- package/skills/roblox-networking/references/remote-validator.luau +193 -0
- package/skills/roblox-publish-checklist/SKILL.md +128 -0
- package/skills/roblox-runtime/SKILL.md +753 -0
- package/skills/roblox-sharp-edges/SKILL.md +295 -0
- package/skills/roblox-sync/SKILL.md +126 -0
- package/skills/roblox-testing/SKILL.md +943 -0
- package/skills/roblox-tooling/SKILL.md +150 -0
- package/vendor/LICENSES/ProfileStore-LICENSE +201 -0
- package/vendor/LICENSES/RbxUtil-LICENSE +7 -0
- package/vendor/LICENSES/promise-LICENSE +21 -0
- package/vendor/LICENSES/t-LICENSE +21 -0
- package/vendor/LICENSES/testez-LICENSE +201 -0
- package/vendor/README.md +84 -0
- package/vendor/fusion/Animation/ExternalTime.luau +84 -0
- package/vendor/fusion/Animation/Spring.luau +322 -0
- package/vendor/fusion/Animation/Stopwatch.luau +128 -0
- package/vendor/fusion/Animation/Tween.luau +187 -0
- package/vendor/fusion/Animation/getTweenDuration.luau +27 -0
- package/vendor/fusion/Animation/getTweenRatio.luau +47 -0
- package/vendor/fusion/Animation/lerpType.luau +164 -0
- package/vendor/fusion/Animation/packType.luau +100 -0
- package/vendor/fusion/Animation/springCoefficients.luau +80 -0
- package/vendor/fusion/Animation/unpackType.luau +103 -0
- package/vendor/fusion/Colour/Oklab.luau +70 -0
- package/vendor/fusion/Colour/sRGB.luau +55 -0
- package/vendor/fusion/External.luau +168 -0
- package/vendor/fusion/ExternalDebug.luau +70 -0
- package/vendor/fusion/Graph/Observer.luau +114 -0
- package/vendor/fusion/Graph/castToGraph.luau +29 -0
- package/vendor/fusion/Graph/change.luau +81 -0
- package/vendor/fusion/Graph/depend.luau +33 -0
- package/vendor/fusion/Graph/evaluate.luau +56 -0
- package/vendor/fusion/Instances/Attribute.luau +58 -0
- package/vendor/fusion/Instances/AttributeChange.luau +47 -0
- package/vendor/fusion/Instances/AttributeOut.luau +63 -0
- package/vendor/fusion/Instances/Child.luau +21 -0
- package/vendor/fusion/Instances/Children.luau +148 -0
- package/vendor/fusion/Instances/Hydrate.luau +33 -0
- package/vendor/fusion/Instances/New.luau +53 -0
- package/vendor/fusion/Instances/OnChange.luau +50 -0
- package/vendor/fusion/Instances/OnEvent.luau +54 -0
- package/vendor/fusion/Instances/Out.luau +69 -0
- package/vendor/fusion/Instances/applyInstanceProps.luau +149 -0
- package/vendor/fusion/Instances/defaultProps.luau +194 -0
- package/vendor/fusion/LICENSE +21 -0
- package/vendor/fusion/Logging/formatError.luau +49 -0
- package/vendor/fusion/Logging/messages.luau +52 -0
- package/vendor/fusion/Logging/parseError.luau +25 -0
- package/vendor/fusion/Memory/checkLifetime.luau +134 -0
- package/vendor/fusion/Memory/deriveScope.luau +24 -0
- package/vendor/fusion/Memory/deriveScopeImpl.luau +45 -0
- package/vendor/fusion/Memory/doCleanup.luau +79 -0
- package/vendor/fusion/Memory/innerScope.luau +34 -0
- package/vendor/fusion/Memory/legacyCleanup.luau +18 -0
- package/vendor/fusion/Memory/needsDestruction.luau +17 -0
- package/vendor/fusion/Memory/poisonScope.luau +34 -0
- package/vendor/fusion/Memory/scopePool.luau +55 -0
- package/vendor/fusion/Memory/scoped.luau +27 -0
- package/vendor/fusion/Memory/whichLivesLonger.luau +75 -0
- package/vendor/fusion/RobloxExternal.luau +98 -0
- package/vendor/fusion/State/Computed.luau +139 -0
- package/vendor/fusion/State/For/Disassembly.luau +211 -0
- package/vendor/fusion/State/For/ForTypes.luau +30 -0
- package/vendor/fusion/State/For/init.luau +110 -0
- package/vendor/fusion/State/ForKeys.luau +94 -0
- package/vendor/fusion/State/ForPairs.luau +97 -0
- package/vendor/fusion/State/ForValues.luau +94 -0
- package/vendor/fusion/State/Value.luau +88 -0
- package/vendor/fusion/State/castToState.luau +26 -0
- package/vendor/fusion/State/peek.luau +31 -0
- package/vendor/fusion/State/updateAll.luau +1 -0
- package/vendor/fusion/Types.luau +314 -0
- package/vendor/fusion/Utility/Contextual.luau +91 -0
- package/vendor/fusion/Utility/Safe.luau +23 -0
- package/vendor/fusion/Utility/isSimilar.luau +29 -0
- package/vendor/fusion/Utility/merge.luau +35 -0
- package/vendor/fusion/Utility/nameOf.luau +35 -0
- package/vendor/fusion/Utility/never.luau +14 -0
- package/vendor/fusion/Utility/nicknames.luau +11 -0
- package/vendor/fusion/Utility/xtypeof.luau +27 -0
- package/vendor/fusion/init.luau +82 -0
- package/vendor/profilestore/init.luau +2243 -0
- package/vendor/promise/init.luau +1982 -0
- package/vendor/rbxutil/buffer-util/Buffer.test.luau +25 -0
- package/vendor/rbxutil/buffer-util/BufferReader.luau +228 -0
- package/vendor/rbxutil/buffer-util/BufferWriter.luau +269 -0
- package/vendor/rbxutil/buffer-util/DataTypeBuffer.luau +223 -0
- package/vendor/rbxutil/buffer-util/Types.luau +60 -0
- package/vendor/rbxutil/buffer-util/index.d.ts +153 -0
- package/vendor/rbxutil/buffer-util/init.luau +41 -0
- package/vendor/rbxutil/buffer-util/package.json +16 -0
- package/vendor/rbxutil/buffer-util/wally.toml +9 -0
- package/vendor/rbxutil/comm/Client/ClientComm.luau +232 -0
- package/vendor/rbxutil/comm/Client/ClientRemoteProperty.luau +156 -0
- package/vendor/rbxutil/comm/Client/ClientRemoteSignal.luau +109 -0
- package/vendor/rbxutil/comm/Client/init.luau +135 -0
- package/vendor/rbxutil/comm/Server/RemoteProperty.luau +295 -0
- package/vendor/rbxutil/comm/Server/RemoteSignal.luau +211 -0
- package/vendor/rbxutil/comm/Server/ServerComm.luau +211 -0
- package/vendor/rbxutil/comm/Server/init.luau +140 -0
- package/vendor/rbxutil/comm/Types.luau +18 -0
- package/vendor/rbxutil/comm/Util.luau +27 -0
- package/vendor/rbxutil/comm/init.luau +35 -0
- package/vendor/rbxutil/comm/wally.toml +13 -0
- package/vendor/rbxutil/component/init.luau +759 -0
- package/vendor/rbxutil/component/init.test.luau +311 -0
- package/vendor/rbxutil/component/wally.toml +14 -0
- package/vendor/rbxutil/concur/init.luau +542 -0
- package/vendor/rbxutil/concur/init.test.luau +364 -0
- package/vendor/rbxutil/concur/wally.toml +8 -0
- package/vendor/rbxutil/enum-list/init.luau +101 -0
- package/vendor/rbxutil/enum-list/init.test.luau +91 -0
- package/vendor/rbxutil/enum-list/wally.toml +8 -0
- package/vendor/rbxutil/find/index.d.ts +20 -0
- package/vendor/rbxutil/find/init.luau +44 -0
- package/vendor/rbxutil/find/package.json +17 -0
- package/vendor/rbxutil/find/wally.toml +8 -0
- package/vendor/rbxutil/input/Gamepad.luau +559 -0
- package/vendor/rbxutil/input/Keyboard.luau +124 -0
- package/vendor/rbxutil/input/Mouse.luau +278 -0
- package/vendor/rbxutil/input/PreferredInput.luau +91 -0
- package/vendor/rbxutil/input/Touch.luau +120 -0
- package/vendor/rbxutil/input/init.luau +33 -0
- package/vendor/rbxutil/input/wally.toml +12 -0
- package/vendor/rbxutil/loader/index.d.ts +15 -0
- package/vendor/rbxutil/loader/init.luau +137 -0
- package/vendor/rbxutil/loader/wally.toml +8 -0
- package/vendor/rbxutil/log/index.d.ts +38 -0
- package/vendor/rbxutil/log/init.luau +746 -0
- package/vendor/rbxutil/log/wally.toml +8 -0
- package/vendor/rbxutil/net/init.luau +190 -0
- package/vendor/rbxutil/net/wally.toml +8 -0
- package/vendor/rbxutil/option/index.d.ts +44 -0
- package/vendor/rbxutil/option/init.luau +489 -0
- package/vendor/rbxutil/option/init.test.luau +342 -0
- package/vendor/rbxutil/option/wally.toml +8 -0
- package/vendor/rbxutil/pid/index.d.ts +53 -0
- package/vendor/rbxutil/pid/init.luau +195 -0
- package/vendor/rbxutil/pid/package.json +16 -0
- package/vendor/rbxutil/pid/wally.toml +9 -0
- package/vendor/rbxutil/quaternion/index.d.ts +117 -0
- package/vendor/rbxutil/quaternion/init.luau +570 -0
- package/vendor/rbxutil/quaternion/package.json +16 -0
- package/vendor/rbxutil/quaternion/wally.toml +9 -0
- package/vendor/rbxutil/query/index.d.ts +43 -0
- package/vendor/rbxutil/query/init.luau +117 -0
- package/vendor/rbxutil/query/package.json +18 -0
- package/vendor/rbxutil/query/wally.toml +9 -0
- package/vendor/rbxutil/sequent/index.d.ts +28 -0
- package/vendor/rbxutil/sequent/init.luau +340 -0
- package/vendor/rbxutil/sequent/package.json +16 -0
- package/vendor/rbxutil/sequent/wally.toml +9 -0
- package/vendor/rbxutil/ser/init.luau +175 -0
- package/vendor/rbxutil/ser/init.test.luau +50 -0
- package/vendor/rbxutil/ser/wally.toml +11 -0
- package/vendor/rbxutil/shake/index.d.ts +36 -0
- package/vendor/rbxutil/shake/init.luau +532 -0
- package/vendor/rbxutil/shake/init.test.luau +267 -0
- package/vendor/rbxutil/shake/package.json +16 -0
- package/vendor/rbxutil/shake/wally.toml +9 -0
- package/vendor/rbxutil/signal/index.d.ts +100 -0
- package/vendor/rbxutil/signal/init.luau +432 -0
- package/vendor/rbxutil/signal/init.test.luau +190 -0
- package/vendor/rbxutil/signal/package.json +17 -0
- package/vendor/rbxutil/signal/wally.toml +9 -0
- package/vendor/rbxutil/silo/TableWatcher.luau +65 -0
- package/vendor/rbxutil/silo/Util.luau +55 -0
- package/vendor/rbxutil/silo/init.luau +338 -0
- package/vendor/rbxutil/silo/init.test.luau +215 -0
- package/vendor/rbxutil/silo/wally.toml +8 -0
- package/vendor/rbxutil/spring/index.d.ts +40 -0
- package/vendor/rbxutil/spring/init.luau +97 -0
- package/vendor/rbxutil/spring/package.json +17 -0
- package/vendor/rbxutil/spring/wally.toml +8 -0
- package/vendor/rbxutil/stream/index.d.ts +88 -0
- package/vendor/rbxutil/stream/init.luau +597 -0
- package/vendor/rbxutil/stream/package.json +18 -0
- package/vendor/rbxutil/stream/wally.toml +9 -0
- package/vendor/rbxutil/streamable/Streamable.luau +202 -0
- package/vendor/rbxutil/streamable/StreamableUtil.luau +80 -0
- package/vendor/rbxutil/streamable/init.luau +8 -0
- package/vendor/rbxutil/streamable/wally.toml +12 -0
- package/vendor/rbxutil/symbol/init.luau +56 -0
- package/vendor/rbxutil/symbol/init.test.luau +37 -0
- package/vendor/rbxutil/symbol/wally.toml +8 -0
- package/vendor/rbxutil/table-util/init.luau +938 -0
- package/vendor/rbxutil/table-util/init.test.luau +439 -0
- package/vendor/rbxutil/table-util/wally.toml +8 -0
- package/vendor/rbxutil/task-queue/index.d.ts +27 -0
- package/vendor/rbxutil/task-queue/init.luau +97 -0
- package/vendor/rbxutil/task-queue/wally.toml +8 -0
- package/vendor/rbxutil/timer/index.d.ts +81 -0
- package/vendor/rbxutil/timer/init.luau +249 -0
- package/vendor/rbxutil/timer/init.test.luau +73 -0
- package/vendor/rbxutil/timer/wally.toml +11 -0
- package/vendor/rbxutil/tree/index.d.ts +15 -0
- package/vendor/rbxutil/tree/init.luau +137 -0
- package/vendor/rbxutil/tree/wally.toml +8 -0
- package/vendor/rbxutil/trove/index.d.ts +46 -0
- package/vendor/rbxutil/trove/init.luau +787 -0
- package/vendor/rbxutil/trove/init.test.luau +203 -0
- package/vendor/rbxutil/trove/wally.toml +8 -0
- package/vendor/rbxutil/typed-remote/init.luau +196 -0
- package/vendor/rbxutil/typed-remote/wally.toml +8 -0
- package/vendor/rbxutil/wait-for/index.d.ts +17 -0
- package/vendor/rbxutil/wait-for/init.luau +257 -0
- package/vendor/rbxutil/wait-for/init.test.luau +182 -0
- package/vendor/rbxutil/wait-for/wally.toml +11 -0
- package/vendor/t/t.lua +1350 -0
- package/vendor/testez/Context.lua +26 -0
- package/vendor/testez/Expectation.lua +311 -0
- package/vendor/testez/ExpectationContext.lua +38 -0
- package/vendor/testez/LifecycleHooks.lua +89 -0
- package/vendor/testez/Reporters/TeamCityReporter.lua +102 -0
- package/vendor/testez/Reporters/TextReporter.lua +106 -0
- package/vendor/testez/Reporters/TextReporterQuiet.lua +97 -0
- package/vendor/testez/TestBootstrap.lua +147 -0
- package/vendor/testez/TestEnum.lua +28 -0
- package/vendor/testez/TestPlan.lua +304 -0
- package/vendor/testez/TestPlanner.lua +40 -0
- package/vendor/testez/TestResults.lua +112 -0
- package/vendor/testez/TestRunner.lua +188 -0
- package/vendor/testez/TestSession.lua +243 -0
- 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,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;
|