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,559 @@
1
+ -- Gamepad
2
+ -- Stephen Leitnick
3
+ -- December 23, 2021
4
+
5
+ local Signal = require(script.Parent.Parent.Signal)
6
+ local Trove = require(script.Parent.Parent.Trove)
7
+
8
+ local GuiService = game:GetService("GuiService")
9
+ local HapticService = game:GetService("HapticService")
10
+ local RunService = game:GetService("RunService")
11
+ local UserInputService = game:GetService("UserInputService")
12
+
13
+ local function ApplyDeadzone(value: number, threshold: number): number
14
+ if math.abs(value) < threshold then
15
+ return 0
16
+ end
17
+ return ((math.abs(value) - threshold) / (1 - threshold)) * math.sign(value)
18
+ end
19
+
20
+ local function GetActiveGamepad(): Enum.UserInputType?
21
+ local activeGamepad = nil
22
+ local navGamepads = UserInputService:GetNavigationGamepads()
23
+ if #navGamepads > 1 then
24
+ for _, navGamepad in navGamepads do
25
+ if activeGamepad == nil or navGamepad.Value < activeGamepad.Value then
26
+ activeGamepad = navGamepad
27
+ end
28
+ end
29
+ else
30
+ local connectedGamepads = UserInputService:GetConnectedGamepads()
31
+ for _, connectedGamepad in connectedGamepads do
32
+ if activeGamepad == nil or connectedGamepad.Value < activeGamepad.Value then
33
+ activeGamepad = connectedGamepad
34
+ end
35
+ end
36
+ end
37
+ if activeGamepad and not UserInputService:GetGamepadConnected(activeGamepad) then
38
+ activeGamepad = nil
39
+ end
40
+ return activeGamepad
41
+ end
42
+
43
+ local function HeartbeatDelay(duration: number, callback: () -> nil): RBXScriptConnection
44
+ local start = time()
45
+ local connection
46
+ connection = RunService.Heartbeat:Connect(function()
47
+ local elapsed = time() - start
48
+ if elapsed >= duration then
49
+ connection:Disconnect()
50
+ callback()
51
+ end
52
+ end)
53
+ return connection
54
+ end
55
+
56
+ --[=[
57
+ @class Gamepad
58
+ @client
59
+
60
+ The Gamepad class is part of the Input package.
61
+
62
+ ```lua
63
+ local Gamepad = require(packages.Input).Gamepad
64
+
65
+ local gamepad = Gamepad.new()
66
+ ```
67
+ ]=]
68
+ local Gamepad = {}
69
+ Gamepad.__index = Gamepad
70
+
71
+ --[=[
72
+ @within Gamepad
73
+ @prop ButtonDown Signal<(button: Enum.KeyCode, processed: boolean)>
74
+ @readonly
75
+ The ButtonDown signal fires when a gamepad button is pressed
76
+ down. The pressed KeyCode is passed to the signal, along with
77
+ whether or not the event was processed.
78
+
79
+ ```lua
80
+ gamepad.ButtonDown:Connect(function(button: Enum.KeyCode, processed: boolean)
81
+ print("Button down", button, processed)
82
+ end)
83
+ ```
84
+ ]=]
85
+
86
+ --[=[
87
+ @within Gamepad
88
+ @prop ButtonUp Signal<(button: Enum.KeyCode, processed: boolean)>
89
+ @readonly
90
+ The ButtonUp signal fires when a gamepad button is released.
91
+ The released KeyCode is passed to the signal, along with
92
+ whether or not the event was processed.
93
+
94
+ ```lua
95
+ gamepad.ButtonUp:Connect(function(button: Enum.KeyCode, processed: boolean)
96
+ print("Button up", button, processed)
97
+ end)
98
+ ```
99
+ ]=]
100
+
101
+ --[=[
102
+ @within Gamepad
103
+ @prop Connected Signal
104
+ @readonly
105
+ Fires when the gamepad is connected. This will _not_ fire if the
106
+ active gamepad is switched. To detect switching to different
107
+ active gamepads, use the `GamepadChanged` signal.
108
+
109
+ There is also a `gamepad:IsConnected()` method.
110
+
111
+ ```lua
112
+ gamepad.Connected:Connect(function()
113
+ print("Connected")
114
+ end)
115
+ ```
116
+ ]=]
117
+
118
+ --[=[
119
+ @within Gamepad
120
+ @prop Disconnected Signal
121
+ @readonly
122
+ Fires when the gamepad is disconnected. This will _not_ fire if the
123
+ active gamepad is switched. To detect switching to different
124
+ active gamepads, use the `GamepadChanged` signal.
125
+
126
+ There is also a `gamepad:IsConnected()` method.
127
+
128
+ ```lua
129
+ gamepad.Disconnected:Connect(function()
130
+ print("Disconnected")
131
+ end)
132
+ ```
133
+ ]=]
134
+
135
+ --[=[
136
+ @within Gamepad
137
+ @prop GamepadChanged Signal<gamepad: Enum.UserInputType>
138
+ @readonly
139
+ Fires when the active gamepad switches. Internally, the gamepad
140
+ object will always wrap around the active gamepad, so nothing
141
+ needs to be changed.
142
+
143
+ ```lua
144
+ gamepad.GamepadChanged:Connect(function(newGamepad: Enum.UserInputType)
145
+ print("Active gamepad changed to:", newGamepad)
146
+ end)
147
+ ```
148
+ ]=]
149
+
150
+ --[=[
151
+ @within Gamepad
152
+ @prop DefaultDeadzone number
153
+
154
+ :::info Default
155
+ Defaults to `0.05`
156
+ :::
157
+
158
+ The default deadzone used for trigger and thumbstick
159
+ analog readings. It is usually best to set this to
160
+ a small value, or allow players to set this option
161
+ themselves in an in-game settings menu.
162
+
163
+ The `GetThumbstick` and `GetTrigger` methods also allow
164
+ a deadzone value to be passed in, which overrides this
165
+ value.
166
+ ]=]
167
+
168
+ --[=[
169
+ @within Gamepad
170
+ @prop SupportsVibration boolean
171
+ @readonly
172
+ Flag to indicate if the currently-active gamepad supports
173
+ haptic motor vibration.
174
+
175
+ It is safe to use the motor methods on the gamepad without
176
+ checking this value, but nothing will happen if the motors
177
+ are not supported.
178
+ ]=]
179
+
180
+ --[=[
181
+ @within Gamepad
182
+ @prop State GamepadState
183
+ @readonly
184
+ Maps KeyCodes to the matching InputObjects within the gamepad.
185
+ These can be used to directly read the current input state of
186
+ a given part of the gamepad. For most cases, the given methods
187
+ and properties of `Gamepad` should make use of this table quite
188
+ rare, but it is provided for special use-cases that might occur.
189
+
190
+ :::note Do Not Cache
191
+ These state objects will change if the active gamepad changes.
192
+ Because a player might switch up gamepads during playtime, it cannot
193
+ be assumed that these state objects will always be the same. Thus
194
+ they should be accessed directly from this `State` table anytime they
195
+ need to be used.
196
+ :::
197
+
198
+ ```lua
199
+ local leftThumbstick = gamepad.State[Enum.KeyCode.Thumbstick1]
200
+ print(leftThumbstick.Position)
201
+ -- It would be better to use gamepad:GetThumbstick(Enum.KeyCode.Thumbstick1),
202
+ -- but this is just an example of direct state access.
203
+ ```
204
+ ]=]
205
+
206
+ --[=[
207
+ @within Gamepad
208
+ @type GamepadState {[Enum.KeyCode]: InputObject}
209
+ ]=]
210
+
211
+ --[=[
212
+ @param gamepad Enum.UserInputType?
213
+ @return Gamepad
214
+ Constructs a gamepad object.
215
+
216
+ If no gamepad UserInputType is provided, this object will always wrap
217
+ around the currently-active gamepad, even if it changes. In most cases
218
+ where input is needed from just the primary gamepad used by the player,
219
+ leaving the `gamepad` argument blank is preferred.
220
+
221
+ Only include the `gamepad` argument when it is necessary to hard-lock
222
+ the object to a specific gamepad input type.
223
+
224
+ ```lua
225
+ -- In most cases, construct the gamepad as such:
226
+ local gamepad = Gamepad.new()
227
+
228
+ -- If the exact UserInputType gamepad is needed, pass it as such:
229
+ local gamepad = Gamepad.new(Enum.UserInputType.Gamepad1)
230
+ ```
231
+ ]=]
232
+ function Gamepad.new(gamepad: Enum.UserInputType?)
233
+ local self = setmetatable({}, Gamepad)
234
+
235
+ self._trove = Trove.new()
236
+ self._gamepadTrove = self._trove:Construct(Trove)
237
+ self.ButtonDown = self._trove:Construct(Signal)
238
+ self.ButtonUp = self._trove:Construct(Signal)
239
+ self.Connected = self._trove:Construct(Signal)
240
+ self.Disconnected = self._trove:Construct(Signal)
241
+ self.GamepadChanged = self._trove:Construct(Signal)
242
+ self.DefaultDeadzone = 0.05
243
+ self.SupportsVibration = false
244
+ self.State = {}
245
+
246
+ self:_setupGamepad(gamepad)
247
+ self:_setupMotors()
248
+
249
+ return self
250
+ end
251
+
252
+ function Gamepad:_setupActiveGamepad(gamepad: Enum.UserInputType?)
253
+ local lastGamepad = self._gamepad
254
+ if gamepad == lastGamepad then
255
+ return
256
+ end
257
+
258
+ self._gamepadTrove:Clean()
259
+ table.clear(self.State)
260
+ self.SupportsVibration = if gamepad then HapticService:IsVibrationSupported(gamepad) else false
261
+
262
+ self._gamepad = gamepad
263
+
264
+ -- Stop if disconnected:
265
+ if not gamepad then
266
+ self.Disconnected:Fire()
267
+ self.GamepadChanged:Fire(nil)
268
+ return
269
+ end
270
+
271
+ for _, inputObject in UserInputService:GetGamepadState(gamepad) do
272
+ self.State[inputObject.KeyCode] = inputObject
273
+ end
274
+
275
+ self._gamepadTrove:Add(self, "StopMotors")
276
+
277
+ self._gamepadTrove:Connect(UserInputService.InputBegan, function(input, processed)
278
+ if input.UserInputType == gamepad then
279
+ self.ButtonDown:Fire(input.KeyCode, processed)
280
+ end
281
+ end)
282
+
283
+ self._gamepadTrove:Connect(UserInputService.InputEnded, function(input, processed)
284
+ if input.UserInputType == gamepad then
285
+ self.ButtonUp:Fire(input.KeyCode, processed)
286
+ end
287
+ end)
288
+
289
+ if lastGamepad == nil then
290
+ self.Connected:Fire()
291
+ end
292
+ self.GamepadChanged:Fire(gamepad)
293
+ end
294
+
295
+ function Gamepad:_setupGamepad(forcedGamepad: Enum.UserInputType?)
296
+ if forcedGamepad then
297
+ -- Forced gamepad:
298
+
299
+ self._trove:Connect(UserInputService.GamepadConnected, function(gp)
300
+ if gp == forcedGamepad then
301
+ self:_setupActiveGamepad(forcedGamepad)
302
+ end
303
+ end)
304
+
305
+ self._trove:Connect(UserInputService.GamepadDisconnected, function(gp)
306
+ if gp == forcedGamepad then
307
+ self:_setupActiveGamepad(nil)
308
+ end
309
+ end)
310
+
311
+ if UserInputService:GetGamepadConnected(forcedGamepad) then
312
+ self:_setupActiveGamepad(forcedGamepad)
313
+ end
314
+ else
315
+ -- Dynamic gamepad:
316
+
317
+ local function CheckToSetupActive()
318
+ local active = GetActiveGamepad()
319
+ if active ~= self._gamepad then
320
+ self:_setupActiveGamepad(active)
321
+ end
322
+ end
323
+
324
+ self._trove:Connect(UserInputService.GamepadConnected, CheckToSetupActive)
325
+ self._trove:Connect(UserInputService.GamepadDisconnected, CheckToSetupActive)
326
+ self:_setupActiveGamepad(GetActiveGamepad())
327
+ end
328
+ end
329
+
330
+ function Gamepad:_setupMotors()
331
+ self._setMotorIds = {}
332
+ for _, motor in Enum.VibrationMotor:GetEnumItems() do
333
+ self._setMotorIds[motor] = 0
334
+ end
335
+ end
336
+
337
+ --[=[
338
+ @param thumbstick Enum.KeyCode
339
+ @param deadzoneThreshold number?
340
+ @return Vector2
341
+ Gets the position of the given thumbstick. The two thumbstick
342
+ KeyCodes are `Enum.KeyCode.Thumbstick1` and `Enum.KeyCode.Thumbstick2`.
343
+
344
+ If `deadzoneThreshold` is not included, the `DefaultDeadzone` value is
345
+ used instead.
346
+
347
+ ```lua
348
+ local leftThumbstick = gamepad:GetThumbstick(Enum.KeyCode.Thumbstick1)
349
+ print("Left thumbstick position", leftThumbstick)
350
+ ```
351
+ ]=]
352
+ function Gamepad:GetThumbstick(thumbstick: Enum.KeyCode, deadzoneThreshold: number?): Vector2
353
+ local pos = self.State[thumbstick].Position
354
+ local deadzone = deadzoneThreshold or self.DefaultDeadzone
355
+ return Vector2.new(ApplyDeadzone(pos.X, deadzone), ApplyDeadzone(pos.Y, deadzone))
356
+ end
357
+
358
+ --[=[
359
+ @param trigger KeyCode
360
+ @param deadzoneThreshold number?
361
+ @return number
362
+ Gets the position of the given trigger. The triggers are usually going
363
+ to be `Enum.KeyCode.ButtonL2` and `Enum.KeyCode.ButtonR2`. These trigger
364
+ buttons are analog, and will output a value between the range of [0, 1].
365
+
366
+ If `deadzoneThreshold` is not included, the `DefaultDeadzone` value is
367
+ used instead.
368
+
369
+ ```lua
370
+ local triggerAmount = gamepad:GetTrigger(Enum.KeyCode.ButtonR2)
371
+ print(triggerAmount)
372
+ ```
373
+ ]=]
374
+ function Gamepad:GetTrigger(trigger: Enum.KeyCode, deadzoneThreshold: number?): number
375
+ return ApplyDeadzone(self.State[trigger].Position.Z, deadzoneThreshold or self.DefaultDeadzone)
376
+ end
377
+
378
+ --[=[
379
+ @param gamepadButton KeyCode
380
+ @return boolean
381
+ Returns `true` if the given button is down. This includes
382
+ any button on the gamepad, such as `Enum.KeyCode.ButtonA`,
383
+ `Enum.KeyCode.ButtonL3`, `Enum.KeyCode.DPadUp`, etc.
384
+
385
+ ```lua
386
+ -- Check if the 'A' button is down:
387
+ if gamepad:IsButtonDown(Enum.KeyCode.ButtonA) then
388
+ print("ButtonA is down")
389
+ end
390
+ ```
391
+ ]=]
392
+ function Gamepad:IsButtonDown(gamepadButton: Enum.KeyCode): boolean
393
+ return UserInputService:IsGamepadButtonDown(self._gamepad, gamepadButton)
394
+ end
395
+
396
+ --[=[
397
+ @param motor Enum.VibrationMotor
398
+ @return boolean
399
+ Returns `true` if the given motor is supported.
400
+
401
+ ```lua
402
+ -- Pulse the trigger (e.g. shooting a weapon), but fall back to
403
+ -- the large motor if not supported:
404
+ local motor = Enum.VibrationMotor.Large
405
+ if gamepad:IsMotorSupported(Enum.VibrationMotor.RightTrigger) then
406
+ motor = Enum.VibrationMotor.RightTrigger
407
+ end
408
+ gamepad:PulseMotor(motor, 1, 0.1)
409
+ ```
410
+ ]=]
411
+ function Gamepad:IsMotorSupported(motor: Enum.VibrationMotor): boolean
412
+ return HapticService:IsMotorSupported(self._gamepad, motor)
413
+ end
414
+
415
+ --[=[
416
+ @param motor Enum.VibrationMotor
417
+ @param intensity number
418
+ Sets the gamepad's haptic motor to a certain intensity. The
419
+ intensity value is a number in the range of [0, 1].
420
+
421
+ ```lua
422
+ gamepad:SetMotor(Enum.VibrationMotor.Large, 0.5)
423
+ ```
424
+ ]=]
425
+ function Gamepad:SetMotor(motor: Enum.VibrationMotor, intensity: number): number
426
+ self._setMotorIds[motor] += 1
427
+ local id = self._setMotorIds[motor]
428
+ HapticService:SetMotor(self._gamepad, motor, intensity)
429
+
430
+ return id
431
+ end
432
+
433
+ --[=[
434
+ @param motor Enum.VibrationMotor
435
+ @param intensity number
436
+ @param duration number
437
+ Sets the gamepad's haptic motor to a certain intensity for a given
438
+ period of time. The motor will stop vibrating after the given
439
+ `duration` has elapsed.
440
+
441
+ Calling any motor setter methods (e.g. `SetMotor`, `PulseMotor`,
442
+ `StopMotor`) _after_ calling this method will override the pulse.
443
+ For instance, if `PulseMotor` is called, and then `SetMotor` is
444
+ called right afterwards, `SetMotor` will take precedent.
445
+
446
+ ```lua
447
+ -- Pulse the large motor for 0.2 seconds with an intensity of 90%:
448
+ gamepad:PulseMotor(Enum.VibrationMotor.Large, 0.9, 0.2)
449
+
450
+ -- Example of PulseMotor being overridden:
451
+ gamepad:PulseMotor(Enum.VibrationMotor.Large, 1, 3)
452
+ task.wait(0.1)
453
+ gamepad:SetMotor(Enum.VibrationMotor.Large, 0.5)
454
+ -- Now the pulse won't shut off the motor after 3 seconds,
455
+ -- because SetMotor was called, which cancels the pulse.
456
+ ```
457
+ ]=]
458
+ function Gamepad:PulseMotor(motor: Enum.VibrationMotor, intensity: number, duration: number)
459
+ local id = self:SetMotor(motor, intensity)
460
+
461
+ local heartbeat = HeartbeatDelay(duration, function()
462
+ if self._setMotorIds[motor] ~= id then
463
+ return
464
+ end
465
+ self:StopMotor(motor)
466
+ end)
467
+
468
+ self._gamepadTrove:Add(heartbeat)
469
+ end
470
+
471
+ --[=[
472
+ @param motor Enum.VibrationMotor
473
+ Stops the given motor. This is equivalent to calling
474
+ `gamepad:SetMotor(motor, 0)`.
475
+
476
+ ```lua
477
+ gamepad:SetMotor(Enum.VibrationMotor.Large, 1)
478
+ task.wait(0.1)
479
+ gamepad:StopMotor(Enum.VibrationMotor.Large)
480
+ ```
481
+ ]=]
482
+ function Gamepad:StopMotor(motor: Enum.VibrationMotor)
483
+ self:SetMotor(motor, 0)
484
+ end
485
+
486
+ --[=[
487
+ Stops all motors on the gamepad.
488
+
489
+ ```lua
490
+ gamepad:SetMotor(Enum.VibrationMotor.Large, 1)
491
+ gamepad:SetMotor(Enum.VibrationMotor.Small, 1)
492
+ task.wait(0.1)
493
+ gamepad:StopMotors()
494
+ ```
495
+ ]=]
496
+ function Gamepad:StopMotors()
497
+ for _, motor in Enum.VibrationMotor:GetEnumItems() do
498
+ if self:IsMotorSupported(motor) then
499
+ self:StopMotor(motor)
500
+ end
501
+ end
502
+ end
503
+
504
+ --[=[
505
+ @return boolean
506
+ Returns `true` if the gamepad is currently connected.
507
+ ]=]
508
+ function Gamepad:IsConnected(): boolean
509
+ return if self._gamepad then UserInputService:GetGamepadConnected(self._gamepad) else false
510
+ end
511
+
512
+ --[=[
513
+ @return Enum.UserInputType?
514
+ Gets the current gamepad UserInputType that the gamepad object
515
+ is using. This will be `nil` if there is no connected gamepad.
516
+ ]=]
517
+ function Gamepad:GetUserInputType(): Enum.UserInputType?
518
+ return self._gamepad
519
+ end
520
+
521
+ --[=[
522
+ @param enabled boolean
523
+ Sets the [`GuiService.AutoSelectGuiEnabled`](https://developer.roblox.com/en-us/api-reference/property/GuiService/AutoSelectGuiEnabled)
524
+ property.
525
+
526
+ This sets whether or not the Select button on a gamepad will try to auto-select
527
+ a GUI object on screen. This does _not_ turn on/off GUI gamepad navigation,
528
+ but just the initial selection using the Select button.
529
+
530
+ For UX purposes, it usually is preferred to set this to `false` and then
531
+ manually set the [`GuiService.SelectedObject`](https://developer.roblox.com/en-us/api-reference/property/GuiService/SelectedObject)
532
+ property within code to set the selected object for gamepads.
533
+
534
+ ```lua
535
+ gamepad:SetAutoSelectGui(false)
536
+ game:GetService("GuiService").SelectedObject = someGuiObject
537
+ ```
538
+ ]=]
539
+ function Gamepad:SetAutoSelectGui(enabled: boolean)
540
+ GuiService.AutoSelectGuiEnabled = enabled
541
+ end
542
+
543
+ --[=[
544
+ @return boolean
545
+ Returns the [`GuiService.AutoSelectGuiEnabled`](https://developer.roblox.com/en-us/api-reference/property/GuiService/AutoSelectGuiEnabled)
546
+ property.
547
+ ]=]
548
+ function Gamepad:IsAutoSelectGuiEnabled(): boolean
549
+ return GuiService.AutoSelectGuiEnabled
550
+ end
551
+
552
+ --[=[
553
+ Destroys the gamepad object.
554
+ ]=]
555
+ function Gamepad:Destroy()
556
+ self._trove:Destroy()
557
+ end
558
+
559
+ return Gamepad
@@ -0,0 +1,124 @@
1
+ -- Keyboard
2
+ -- Stephen Leitnick
3
+ -- October 10, 2021
4
+
5
+ local Signal = require(script.Parent.Parent.Signal)
6
+ local Trove = require(script.Parent.Parent.Trove)
7
+
8
+ local UserInputService = game:GetService("UserInputService")
9
+
10
+ --[=[
11
+ @class Keyboard
12
+ @client
13
+
14
+ The Keyboard class is part of the Input package.
15
+
16
+ ```lua
17
+ local Keyboard = require(packages.Input).Keyboard
18
+ ```
19
+ ]=]
20
+ local Keyboard = {}
21
+ Keyboard.__index = Keyboard
22
+
23
+ --[=[
24
+ @within Keyboard
25
+ @prop KeyDown Signal<Enum.KeyCode, boolean>
26
+ @tag Event
27
+ Fired when a key is pressed.
28
+ ```lua
29
+ keyboard.KeyDown:Connect(function(key: KeyCode)
30
+ print("Key pressed", key)
31
+ end)
32
+ ```
33
+ ]=]
34
+ --[=[
35
+ @within Keyboard
36
+ @prop KeyUp Signal<Enum.KeyCode, boolean>
37
+ @tag Event
38
+ Fired when a key is released.
39
+ ```lua
40
+ keyboard.KeyUp:Connect(function(key: KeyCode)
41
+ print("Key released", key)
42
+ end)
43
+ ```
44
+ ]=]
45
+
46
+ --[=[
47
+ @return Keyboard
48
+
49
+ Constructs a new keyboard input capturer.
50
+
51
+ ```lua
52
+ local keyboard = Keyboard.new()
53
+ ```
54
+ ]=]
55
+ function Keyboard.new()
56
+ local self = setmetatable({}, Keyboard)
57
+ self._trove = Trove.new()
58
+ self.KeyDown = self._trove:Construct(Signal)
59
+ self.KeyUp = self._trove:Construct(Signal)
60
+ self:_setup()
61
+ return self
62
+ end
63
+
64
+ --[=[
65
+ Check if the given key is down.
66
+
67
+ ```lua
68
+ local w = keyboard:IsKeyDown(Enum.KeyCode.W)
69
+ if w then ... end
70
+ ```
71
+ ]=]
72
+ function Keyboard:IsKeyDown(keyCode: Enum.KeyCode): boolean
73
+ return UserInputService:IsKeyDown(keyCode)
74
+ end
75
+
76
+ --[=[
77
+ Check if _both_ keys are down. Useful for key combinations.
78
+
79
+ ```lua
80
+ local shiftA = keyboard:AreKeysDown(Enum.KeyCode.LeftShift, Enum.KeyCode.A)
81
+ if shiftA then ... end
82
+ ```
83
+ ]=]
84
+ function Keyboard:AreKeysDown(keyCodeOne: Enum.KeyCode, keyCodeTwo: Enum.KeyCode): boolean
85
+ return self:IsKeyDown(keyCodeOne) and self:IsKeyDown(keyCodeTwo)
86
+ end
87
+
88
+ --[=[
89
+ Check if _either_ of the keys are down. Useful when two keys might perform
90
+ the same operation.
91
+
92
+ ```lua
93
+ local wOrUp = keyboard:AreEitherKeysDown(Enum.KeyCode.W, Enum.KeyCode.Up)
94
+ if wOrUp then
95
+ -- Go forward
96
+ end
97
+ ```
98
+ ]=]
99
+ function Keyboard:AreEitherKeysDown(keyCodeOne: Enum.KeyCode, keyCodeTwo: Enum.KeyCode): boolean
100
+ return self:IsKeyDown(keyCodeOne) or self:IsKeyDown(keyCodeTwo)
101
+ end
102
+
103
+ function Keyboard:_setup()
104
+ self._trove:Connect(UserInputService.InputBegan, function(input, processed)
105
+ if input.UserInputType == Enum.UserInputType.Keyboard then
106
+ self.KeyDown:Fire(input.KeyCode, processed)
107
+ end
108
+ end)
109
+
110
+ self._trove:Connect(UserInputService.InputEnded, function(input, processed)
111
+ if input.UserInputType == Enum.UserInputType.Keyboard then
112
+ self.KeyUp:Fire(input.KeyCode, processed)
113
+ end
114
+ end)
115
+ end
116
+
117
+ --[=[
118
+ Destroy the keyboard input capturer.
119
+ ]=]
120
+ function Keyboard:Destroy()
121
+ self._trove:Destroy()
122
+ end
123
+
124
+ return Keyboard