roblox-opencode 1.0.0 → 1.0.1

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 (246) hide show
  1. package/README.md +112 -122
  2. package/commands/setup-game.md +108 -108
  3. package/commands/sync-check.md +53 -53
  4. package/core/roblox-core.md +93 -93
  5. package/dist/server.js +189 -167
  6. package/package.json +35 -35
  7. package/skills/roblox-analytics/SKILL.md +277 -277
  8. package/skills/roblox-analytics/references/event-batcher.luau +75 -75
  9. package/skills/roblox-animation-vfx/SKILL.md +1325 -1325
  10. package/skills/roblox-architecture/SKILL.md +863 -863
  11. package/skills/roblox-architecture/references/combat-systems.md +1381 -1381
  12. package/skills/roblox-code-review/SKILL.md +686 -686
  13. package/skills/roblox-data/SKILL.md +889 -889
  14. package/skills/roblox-data/references/inventory-systems.md +1729 -1729
  15. package/skills/roblox-debug/SKILL.md +98 -98
  16. package/skills/roblox-gui/SKILL.md +1103 -1103
  17. package/skills/roblox-gui-fusion/SKILL.md +150 -150
  18. package/skills/roblox-gui-fusion/references/inventory.luau +427 -427
  19. package/skills/roblox-gui-fusion/references/settings-menu.luau +579 -579
  20. package/skills/roblox-gui-fusion/references/shop.luau +411 -411
  21. package/skills/roblox-luau-mastery/SKILL.md +1519 -1519
  22. package/skills/roblox-monetization/SKILL.md +1084 -1084
  23. package/skills/roblox-monetization/references/process-receipt.luau +131 -131
  24. package/skills/roblox-networking/SKILL.md +669 -669
  25. package/skills/roblox-networking/references/remote-validator.luau +193 -193
  26. package/skills/roblox-publish-checklist/SKILL.md +127 -127
  27. package/skills/roblox-runtime/SKILL.md +753 -753
  28. package/skills/roblox-sharp-edges/SKILL.md +294 -294
  29. package/skills/roblox-sync/SKILL.md +126 -126
  30. package/skills/roblox-testing/SKILL.md +943 -943
  31. package/skills/roblox-tooling/SKILL.md +149 -149
  32. package/vendor/LICENSES/ProfileStore-LICENSE +201 -201
  33. package/vendor/LICENSES/RbxUtil-LICENSE +7 -7
  34. package/vendor/LICENSES/promise-LICENSE +20 -20
  35. package/vendor/LICENSES/t-LICENSE +21 -21
  36. package/vendor/LICENSES/testez-LICENSE +200 -200
  37. package/vendor/README.md +83 -83
  38. package/vendor/fusion/Animation/ExternalTime.luau +83 -83
  39. package/vendor/fusion/Animation/Spring.luau +321 -321
  40. package/vendor/fusion/Animation/Stopwatch.luau +127 -127
  41. package/vendor/fusion/Animation/Tween.luau +187 -187
  42. package/vendor/fusion/Animation/getTweenDuration.luau +27 -27
  43. package/vendor/fusion/Animation/getTweenRatio.luau +47 -47
  44. package/vendor/fusion/Animation/lerpType.luau +163 -163
  45. package/vendor/fusion/Animation/packType.luau +99 -99
  46. package/vendor/fusion/Animation/springCoefficients.luau +80 -80
  47. package/vendor/fusion/Animation/unpackType.luau +102 -102
  48. package/vendor/fusion/Colour/Oklab.luau +70 -70
  49. package/vendor/fusion/Colour/sRGB.luau +54 -54
  50. package/vendor/fusion/External.luau +167 -167
  51. package/vendor/fusion/ExternalDebug.luau +69 -69
  52. package/vendor/fusion/Graph/Observer.luau +113 -113
  53. package/vendor/fusion/Graph/castToGraph.luau +28 -28
  54. package/vendor/fusion/Graph/change.luau +80 -80
  55. package/vendor/fusion/Graph/depend.luau +32 -32
  56. package/vendor/fusion/Graph/evaluate.luau +55 -55
  57. package/vendor/fusion/Instances/Attribute.luau +57 -57
  58. package/vendor/fusion/Instances/AttributeChange.luau +46 -46
  59. package/vendor/fusion/Instances/AttributeOut.luau +63 -63
  60. package/vendor/fusion/Instances/Child.luau +21 -21
  61. package/vendor/fusion/Instances/Children.luau +147 -147
  62. package/vendor/fusion/Instances/Hydrate.luau +32 -32
  63. package/vendor/fusion/Instances/New.luau +52 -52
  64. package/vendor/fusion/Instances/OnChange.luau +49 -49
  65. package/vendor/fusion/Instances/OnEvent.luau +53 -53
  66. package/vendor/fusion/Instances/Out.luau +69 -69
  67. package/vendor/fusion/Instances/applyInstanceProps.luau +148 -148
  68. package/vendor/fusion/Instances/defaultProps.luau +194 -194
  69. package/vendor/fusion/LICENSE +21 -21
  70. package/vendor/fusion/Logging/formatError.luau +48 -48
  71. package/vendor/fusion/Logging/messages.luau +51 -51
  72. package/vendor/fusion/Logging/parseError.luau +24 -24
  73. package/vendor/fusion/Memory/checkLifetime.luau +133 -133
  74. package/vendor/fusion/Memory/deriveScope.luau +23 -23
  75. package/vendor/fusion/Memory/deriveScopeImpl.luau +44 -44
  76. package/vendor/fusion/Memory/doCleanup.luau +78 -78
  77. package/vendor/fusion/Memory/innerScope.luau +33 -33
  78. package/vendor/fusion/Memory/legacyCleanup.luau +17 -17
  79. package/vendor/fusion/Memory/needsDestruction.luau +16 -16
  80. package/vendor/fusion/Memory/poisonScope.luau +33 -33
  81. package/vendor/fusion/Memory/scopePool.luau +54 -54
  82. package/vendor/fusion/Memory/scoped.luau +26 -26
  83. package/vendor/fusion/Memory/whichLivesLonger.luau +74 -74
  84. package/vendor/fusion/RobloxExternal.luau +97 -97
  85. package/vendor/fusion/State/Computed.luau +138 -138
  86. package/vendor/fusion/State/For/Disassembly.luau +210 -210
  87. package/vendor/fusion/State/For/ForTypes.luau +30 -30
  88. package/vendor/fusion/State/For/init.luau +109 -109
  89. package/vendor/fusion/State/ForKeys.luau +93 -93
  90. package/vendor/fusion/State/ForPairs.luau +96 -96
  91. package/vendor/fusion/State/ForValues.luau +93 -93
  92. package/vendor/fusion/State/Value.luau +87 -87
  93. package/vendor/fusion/State/castToState.luau +25 -25
  94. package/vendor/fusion/State/peek.luau +30 -30
  95. package/vendor/fusion/Types.luau +314 -314
  96. package/vendor/fusion/Utility/Contextual.luau +90 -90
  97. package/vendor/fusion/Utility/Safe.luau +22 -22
  98. package/vendor/fusion/Utility/isSimilar.luau +29 -29
  99. package/vendor/fusion/Utility/merge.luau +35 -35
  100. package/vendor/fusion/Utility/nameOf.luau +34 -34
  101. package/vendor/fusion/Utility/never.luau +13 -13
  102. package/vendor/fusion/Utility/nicknames.luau +10 -10
  103. package/vendor/fusion/Utility/xtypeof.luau +26 -26
  104. package/vendor/fusion/init.luau +82 -82
  105. package/vendor/profilestore/init.luau +2242 -2242
  106. package/vendor/promise/init.luau +1982 -1982
  107. package/vendor/rbxutil/buffer-util/Buffer.test.luau +25 -25
  108. package/vendor/rbxutil/buffer-util/BufferReader.luau +228 -228
  109. package/vendor/rbxutil/buffer-util/BufferWriter.luau +269 -269
  110. package/vendor/rbxutil/buffer-util/DataTypeBuffer.luau +223 -223
  111. package/vendor/rbxutil/buffer-util/Types.luau +60 -60
  112. package/vendor/rbxutil/buffer-util/index.d.ts +153 -153
  113. package/vendor/rbxutil/buffer-util/init.luau +41 -41
  114. package/vendor/rbxutil/buffer-util/package.json +16 -16
  115. package/vendor/rbxutil/buffer-util/wally.toml +9 -9
  116. package/vendor/rbxutil/comm/Client/ClientComm.luau +232 -232
  117. package/vendor/rbxutil/comm/Client/ClientRemoteProperty.luau +156 -156
  118. package/vendor/rbxutil/comm/Client/ClientRemoteSignal.luau +109 -109
  119. package/vendor/rbxutil/comm/Client/init.luau +135 -135
  120. package/vendor/rbxutil/comm/Server/RemoteProperty.luau +295 -295
  121. package/vendor/rbxutil/comm/Server/RemoteSignal.luau +211 -211
  122. package/vendor/rbxutil/comm/Server/ServerComm.luau +211 -211
  123. package/vendor/rbxutil/comm/Server/init.luau +140 -140
  124. package/vendor/rbxutil/comm/Types.luau +18 -18
  125. package/vendor/rbxutil/comm/Util.luau +27 -27
  126. package/vendor/rbxutil/comm/init.luau +35 -35
  127. package/vendor/rbxutil/comm/wally.toml +13 -13
  128. package/vendor/rbxutil/component/init.luau +759 -759
  129. package/vendor/rbxutil/component/init.test.luau +311 -311
  130. package/vendor/rbxutil/component/wally.toml +14 -14
  131. package/vendor/rbxutil/concur/init.luau +542 -542
  132. package/vendor/rbxutil/concur/init.test.luau +364 -364
  133. package/vendor/rbxutil/concur/wally.toml +8 -8
  134. package/vendor/rbxutil/enum-list/init.luau +101 -101
  135. package/vendor/rbxutil/enum-list/init.test.luau +91 -91
  136. package/vendor/rbxutil/enum-list/wally.toml +8 -8
  137. package/vendor/rbxutil/find/index.d.ts +20 -20
  138. package/vendor/rbxutil/find/init.luau +44 -44
  139. package/vendor/rbxutil/find/package.json +17 -17
  140. package/vendor/rbxutil/find/wally.toml +8 -8
  141. package/vendor/rbxutil/input/Gamepad.luau +559 -559
  142. package/vendor/rbxutil/input/Keyboard.luau +124 -124
  143. package/vendor/rbxutil/input/Mouse.luau +278 -278
  144. package/vendor/rbxutil/input/PreferredInput.luau +91 -91
  145. package/vendor/rbxutil/input/Touch.luau +120 -120
  146. package/vendor/rbxutil/input/init.luau +33 -33
  147. package/vendor/rbxutil/input/wally.toml +12 -12
  148. package/vendor/rbxutil/loader/index.d.ts +15 -15
  149. package/vendor/rbxutil/loader/init.luau +137 -137
  150. package/vendor/rbxutil/loader/wally.toml +8 -8
  151. package/vendor/rbxutil/log/index.d.ts +38 -38
  152. package/vendor/rbxutil/log/init.luau +746 -746
  153. package/vendor/rbxutil/log/wally.toml +8 -8
  154. package/vendor/rbxutil/net/init.luau +190 -190
  155. package/vendor/rbxutil/net/wally.toml +8 -8
  156. package/vendor/rbxutil/option/index.d.ts +44 -44
  157. package/vendor/rbxutil/option/init.luau +489 -489
  158. package/vendor/rbxutil/option/init.test.luau +342 -342
  159. package/vendor/rbxutil/option/wally.toml +8 -8
  160. package/vendor/rbxutil/pid/index.d.ts +53 -53
  161. package/vendor/rbxutil/pid/init.luau +195 -195
  162. package/vendor/rbxutil/pid/package.json +16 -16
  163. package/vendor/rbxutil/pid/wally.toml +9 -9
  164. package/vendor/rbxutil/quaternion/index.d.ts +117 -117
  165. package/vendor/rbxutil/quaternion/init.luau +570 -570
  166. package/vendor/rbxutil/quaternion/package.json +16 -16
  167. package/vendor/rbxutil/quaternion/wally.toml +9 -9
  168. package/vendor/rbxutil/query/index.d.ts +43 -43
  169. package/vendor/rbxutil/query/init.luau +117 -117
  170. package/vendor/rbxutil/query/package.json +18 -18
  171. package/vendor/rbxutil/query/wally.toml +9 -9
  172. package/vendor/rbxutil/sequent/index.d.ts +28 -28
  173. package/vendor/rbxutil/sequent/init.luau +340 -340
  174. package/vendor/rbxutil/sequent/package.json +16 -16
  175. package/vendor/rbxutil/sequent/wally.toml +9 -9
  176. package/vendor/rbxutil/ser/init.luau +175 -175
  177. package/vendor/rbxutil/ser/init.test.luau +50 -50
  178. package/vendor/rbxutil/ser/wally.toml +11 -11
  179. package/vendor/rbxutil/shake/index.d.ts +36 -36
  180. package/vendor/rbxutil/shake/init.luau +532 -532
  181. package/vendor/rbxutil/shake/init.test.luau +267 -267
  182. package/vendor/rbxutil/shake/package.json +16 -16
  183. package/vendor/rbxutil/shake/wally.toml +9 -9
  184. package/vendor/rbxutil/signal/index.d.ts +100 -100
  185. package/vendor/rbxutil/signal/init.luau +432 -432
  186. package/vendor/rbxutil/signal/init.test.luau +190 -190
  187. package/vendor/rbxutil/signal/package.json +17 -17
  188. package/vendor/rbxutil/signal/wally.toml +9 -9
  189. package/vendor/rbxutil/silo/TableWatcher.luau +65 -65
  190. package/vendor/rbxutil/silo/Util.luau +55 -55
  191. package/vendor/rbxutil/silo/init.luau +338 -338
  192. package/vendor/rbxutil/silo/init.test.luau +215 -215
  193. package/vendor/rbxutil/silo/wally.toml +8 -8
  194. package/vendor/rbxutil/spring/index.d.ts +40 -40
  195. package/vendor/rbxutil/spring/init.luau +97 -97
  196. package/vendor/rbxutil/spring/package.json +17 -17
  197. package/vendor/rbxutil/spring/wally.toml +8 -8
  198. package/vendor/rbxutil/stream/index.d.ts +88 -88
  199. package/vendor/rbxutil/stream/init.luau +597 -597
  200. package/vendor/rbxutil/stream/package.json +18 -18
  201. package/vendor/rbxutil/stream/wally.toml +9 -9
  202. package/vendor/rbxutil/streamable/Streamable.luau +202 -202
  203. package/vendor/rbxutil/streamable/StreamableUtil.luau +80 -80
  204. package/vendor/rbxutil/streamable/init.luau +8 -8
  205. package/vendor/rbxutil/streamable/wally.toml +12 -12
  206. package/vendor/rbxutil/symbol/init.luau +56 -56
  207. package/vendor/rbxutil/symbol/init.test.luau +37 -37
  208. package/vendor/rbxutil/symbol/wally.toml +8 -8
  209. package/vendor/rbxutil/table-util/init.luau +938 -938
  210. package/vendor/rbxutil/table-util/init.test.luau +439 -439
  211. package/vendor/rbxutil/task-queue/index.d.ts +27 -27
  212. package/vendor/rbxutil/task-queue/init.luau +97 -97
  213. package/vendor/rbxutil/task-queue/wally.toml +8 -8
  214. package/vendor/rbxutil/timer/index.d.ts +81 -81
  215. package/vendor/rbxutil/timer/init.luau +249 -249
  216. package/vendor/rbxutil/timer/init.test.luau +73 -73
  217. package/vendor/rbxutil/timer/wally.toml +11 -11
  218. package/vendor/rbxutil/tree/index.d.ts +15 -15
  219. package/vendor/rbxutil/tree/init.luau +137 -137
  220. package/vendor/rbxutil/tree/wally.toml +8 -8
  221. package/vendor/rbxutil/trove/index.d.ts +46 -46
  222. package/vendor/rbxutil/trove/init.luau +787 -787
  223. package/vendor/rbxutil/trove/init.test.luau +203 -203
  224. package/vendor/rbxutil/trove/wally.toml +8 -8
  225. package/vendor/rbxutil/typed-remote/init.luau +196 -196
  226. package/vendor/rbxutil/typed-remote/wally.toml +8 -8
  227. package/vendor/rbxutil/wait-for/index.d.ts +17 -17
  228. package/vendor/rbxutil/wait-for/init.luau +257 -257
  229. package/vendor/rbxutil/wait-for/init.test.luau +182 -182
  230. package/vendor/rbxutil/wait-for/wally.toml +11 -11
  231. package/vendor/t/t.lua +1350 -1350
  232. package/vendor/testez/Context.lua +26 -26
  233. package/vendor/testez/Expectation.lua +311 -311
  234. package/vendor/testez/ExpectationContext.lua +38 -38
  235. package/vendor/testez/LifecycleHooks.lua +89 -89
  236. package/vendor/testez/Reporters/TeamCityReporter.lua +101 -101
  237. package/vendor/testez/Reporters/TextReporter.lua +105 -105
  238. package/vendor/testez/Reporters/TextReporterQuiet.lua +96 -96
  239. package/vendor/testez/TestBootstrap.lua +146 -146
  240. package/vendor/testez/TestEnum.lua +27 -27
  241. package/vendor/testez/TestPlan.lua +304 -304
  242. package/vendor/testez/TestPlanner.lua +39 -39
  243. package/vendor/testez/TestResults.lua +111 -111
  244. package/vendor/testez/TestRunner.lua +188 -188
  245. package/vendor/testez/TestSession.lua +243 -243
  246. package/vendor/testez/init.lua +39 -39
@@ -1,193 +1,193 @@
1
- --[[
2
- RemoteValidator — Production-ready server-side validation module
3
- Source: roblox-opencode/skills/roblox-networking (authored for this harness)
4
-
5
- Drop this into ServerScriptService/Modules/. Require it in every remote handler.
6
- Covers: type checking, range validation, cooldowns, existence checks, distance,
7
- authorization, and cleanup.
8
-
9
- ADAPT THIS: Add game-specific checks (e.g. team validation, game state checks).
10
- The core patterns (validateArgs, checkCooldown, withinRange) are universal.
11
- ]]
12
-
13
- local Players = game:GetService("Players")
14
-
15
- local RemoteValidator = {}
16
-
17
- -------------------------------------------------------------------------------
18
- -- Type Checking
19
- -- Validates that arguments match expected types.
20
- -------------------------------------------------------------------------------
21
-
22
- type TypeSpec = string | (value: any) -> boolean
23
-
24
- function RemoteValidator.checkType(value: any, expected: TypeSpec): boolean
25
- if typeof(expected) == "function" then
26
- return expected(value)
27
- end
28
- return typeof(value) == expected
29
- end
30
-
31
- function RemoteValidator.validateArgs(
32
- args: { any },
33
- schema: { { name: string, type: TypeSpec, optional: boolean? } }
34
- ): (boolean, string?)
35
- for i, spec in schema do
36
- local value = args[i]
37
-
38
- if value == nil then
39
- if not spec.optional then
40
- return false, `Missing required argument: {spec.name}`
41
- end
42
- continue
43
- end
44
-
45
- if not RemoteValidator.checkType(value, spec.type) then
46
- return false, `Invalid type for {spec.name}: expected {tostring(spec.type)}, got {typeof(value)}`
47
- end
48
- end
49
-
50
- -- Reject extra arguments not declared in schema
51
- if #args > #schema then
52
- return false, `Too many arguments: expected {#schema}, got {#args}`
53
- end
54
-
55
- return true, nil
56
- end
57
-
58
- -------------------------------------------------------------------------------
59
- -- Range Checking
60
- -- Validates that numeric values fall within acceptable bounds.
61
- -------------------------------------------------------------------------------
62
-
63
- function RemoteValidator.checkRange(value: number, min: number, max: number): boolean
64
- return typeof(value) == "number"
65
- and value == value -- NaN check
66
- and value >= min
67
- and value <= max
68
- end
69
-
70
- function RemoteValidator.checkIntegerRange(value: number, min: number, max: number): boolean
71
- return RemoteValidator.checkRange(value, min, max)
72
- and math.floor(value) == value
73
- end
74
-
75
- -------------------------------------------------------------------------------
76
- -- Cooldown Tracking
77
- -- Per-player, per-action cooldown enforcement.
78
- -------------------------------------------------------------------------------
79
-
80
- local cooldowns: { [Player]: { [string]: number } } = {}
81
-
82
- function RemoteValidator.checkCooldown(player: Player, action: string, cooldownSeconds: number): boolean
83
- local now = os.clock()
84
- local playerCooldowns = cooldowns[player]
85
-
86
- if not playerCooldowns then
87
- playerCooldowns = {}
88
- cooldowns[player] = playerCooldowns
89
- end
90
-
91
- local lastUsed = playerCooldowns[action]
92
- if lastUsed and (now - lastUsed) < cooldownSeconds then
93
- return false
94
- end
95
-
96
- playerCooldowns[action] = now
97
- return true
98
- end
99
-
100
- function RemoteValidator.clearPlayerCooldowns(player: Player)
101
- cooldowns[player] = nil
102
- end
103
-
104
- -------------------------------------------------------------------------------
105
- -- Existence Checks
106
- -- Validates that targets, objects, and instances actually exist.
107
- -------------------------------------------------------------------------------
108
-
109
- function RemoteValidator.playerExists(playerName: string): Player?
110
- return Players:FindFirstChild(playerName) :: Player?
111
- end
112
-
113
- function RemoteValidator.characterAlive(player: Player): boolean
114
- local character = player.Character
115
- if not character then
116
- return false
117
- end
118
-
119
- local humanoid = character:FindFirstChildOfClass("Humanoid")
120
- if not humanoid then
121
- return false
122
- end
123
-
124
- return humanoid.Health > 0
125
- end
126
-
127
- function RemoteValidator.instanceExists(parent: Instance, name: string, className: string?): Instance?
128
- local child = parent:FindFirstChild(name)
129
- if not child then
130
- return nil
131
- end
132
-
133
- if className and not child:IsA(className) then
134
- return nil
135
- end
136
-
137
- return child
138
- end
139
-
140
- -------------------------------------------------------------------------------
141
- -- Authorization
142
- -- Checks if a player is allowed to perform an action.
143
- -------------------------------------------------------------------------------
144
-
145
- function RemoteValidator.playerOwnsItem(player: Player, itemId: string, inventoryFolder: Folder?): boolean
146
- local folder = inventoryFolder or player:FindFirstChild("Inventory") :: Folder?
147
- if not folder then
148
- return false
149
- end
150
-
151
- return folder:FindFirstChild(itemId) ~= nil
152
- end
153
-
154
- function RemoteValidator.playerHasAttribute(player: Player, attribute: string, expectedValue: any?): boolean
155
- local value = player:GetAttribute(attribute)
156
- if expectedValue ~= nil then
157
- return value == expectedValue
158
- end
159
- return value ~= nil
160
- end
161
-
162
- -------------------------------------------------------------------------------
163
- -- Distance Check
164
- -- Validates that two positions are within an acceptable range.
165
- -------------------------------------------------------------------------------
166
-
167
- function RemoteValidator.withinRange(posA: Vector3, posB: Vector3, maxDistance: number): boolean
168
- return (posA - posB).Magnitude <= maxDistance
169
- end
170
-
171
- function RemoteValidator.playerWithinRange(player: Player, targetPos: Vector3, maxDistance: number): boolean
172
- local character = player.Character
173
- if not character then
174
- return false
175
- end
176
-
177
- local root = character:FindFirstChild("HumanoidRootPart")
178
- if not root then
179
- return false
180
- end
181
-
182
- return RemoteValidator.withinRange(root.Position, targetPos, maxDistance)
183
- end
184
-
185
- -------------------------------------------------------------------------------
186
- -- Cleanup — prevent memory leaks from departed players
187
- -------------------------------------------------------------------------------
188
-
189
- Players.PlayerRemoving:Connect(function(player)
190
- RemoteValidator.clearPlayerCooldowns(player)
191
- end)
192
-
193
- return RemoteValidator
1
+ --[[
2
+ RemoteValidator — Production-ready server-side validation module
3
+ Source: roblox-opencode/skills/roblox-networking (authored for this harness)
4
+
5
+ Drop this into ServerScriptService/Modules/. Require it in every remote handler.
6
+ Covers: type checking, range validation, cooldowns, existence checks, distance,
7
+ authorization, and cleanup.
8
+
9
+ ADAPT THIS: Add game-specific checks (e.g. team validation, game state checks).
10
+ The core patterns (validateArgs, checkCooldown, withinRange) are universal.
11
+ ]]
12
+
13
+ local Players = game:GetService("Players")
14
+
15
+ local RemoteValidator = {}
16
+
17
+ -------------------------------------------------------------------------------
18
+ -- Type Checking
19
+ -- Validates that arguments match expected types.
20
+ -------------------------------------------------------------------------------
21
+
22
+ type TypeSpec = string | (value: any) -> boolean
23
+
24
+ function RemoteValidator.checkType(value: any, expected: TypeSpec): boolean
25
+ if typeof(expected) == "function" then
26
+ return expected(value)
27
+ end
28
+ return typeof(value) == expected
29
+ end
30
+
31
+ function RemoteValidator.validateArgs(
32
+ args: { any },
33
+ schema: { { name: string, type: TypeSpec, optional: boolean? } }
34
+ ): (boolean, string?)
35
+ for i, spec in schema do
36
+ local value = args[i]
37
+
38
+ if value == nil then
39
+ if not spec.optional then
40
+ return false, `Missing required argument: {spec.name}`
41
+ end
42
+ continue
43
+ end
44
+
45
+ if not RemoteValidator.checkType(value, spec.type) then
46
+ return false, `Invalid type for {spec.name}: expected {tostring(spec.type)}, got {typeof(value)}`
47
+ end
48
+ end
49
+
50
+ -- Reject extra arguments not declared in schema
51
+ if #args > #schema then
52
+ return false, `Too many arguments: expected {#schema}, got {#args}`
53
+ end
54
+
55
+ return true, nil
56
+ end
57
+
58
+ -------------------------------------------------------------------------------
59
+ -- Range Checking
60
+ -- Validates that numeric values fall within acceptable bounds.
61
+ -------------------------------------------------------------------------------
62
+
63
+ function RemoteValidator.checkRange(value: number, min: number, max: number): boolean
64
+ return typeof(value) == "number"
65
+ and value == value -- NaN check
66
+ and value >= min
67
+ and value <= max
68
+ end
69
+
70
+ function RemoteValidator.checkIntegerRange(value: number, min: number, max: number): boolean
71
+ return RemoteValidator.checkRange(value, min, max)
72
+ and math.floor(value) == value
73
+ end
74
+
75
+ -------------------------------------------------------------------------------
76
+ -- Cooldown Tracking
77
+ -- Per-player, per-action cooldown enforcement.
78
+ -------------------------------------------------------------------------------
79
+
80
+ local cooldowns: { [Player]: { [string]: number } } = {}
81
+
82
+ function RemoteValidator.checkCooldown(player: Player, action: string, cooldownSeconds: number): boolean
83
+ local now = os.clock()
84
+ local playerCooldowns = cooldowns[player]
85
+
86
+ if not playerCooldowns then
87
+ playerCooldowns = {}
88
+ cooldowns[player] = playerCooldowns
89
+ end
90
+
91
+ local lastUsed = playerCooldowns[action]
92
+ if lastUsed and (now - lastUsed) < cooldownSeconds then
93
+ return false
94
+ end
95
+
96
+ playerCooldowns[action] = now
97
+ return true
98
+ end
99
+
100
+ function RemoteValidator.clearPlayerCooldowns(player: Player)
101
+ cooldowns[player] = nil
102
+ end
103
+
104
+ -------------------------------------------------------------------------------
105
+ -- Existence Checks
106
+ -- Validates that targets, objects, and instances actually exist.
107
+ -------------------------------------------------------------------------------
108
+
109
+ function RemoteValidator.playerExists(playerName: string): Player?
110
+ return Players:FindFirstChild(playerName) :: Player?
111
+ end
112
+
113
+ function RemoteValidator.characterAlive(player: Player): boolean
114
+ local character = player.Character
115
+ if not character then
116
+ return false
117
+ end
118
+
119
+ local humanoid = character:FindFirstChildOfClass("Humanoid")
120
+ if not humanoid then
121
+ return false
122
+ end
123
+
124
+ return humanoid.Health > 0
125
+ end
126
+
127
+ function RemoteValidator.instanceExists(parent: Instance, name: string, className: string?): Instance?
128
+ local child = parent:FindFirstChild(name)
129
+ if not child then
130
+ return nil
131
+ end
132
+
133
+ if className and not child:IsA(className) then
134
+ return nil
135
+ end
136
+
137
+ return child
138
+ end
139
+
140
+ -------------------------------------------------------------------------------
141
+ -- Authorization
142
+ -- Checks if a player is allowed to perform an action.
143
+ -------------------------------------------------------------------------------
144
+
145
+ function RemoteValidator.playerOwnsItem(player: Player, itemId: string, inventoryFolder: Folder?): boolean
146
+ local folder = inventoryFolder or player:FindFirstChild("Inventory") :: Folder?
147
+ if not folder then
148
+ return false
149
+ end
150
+
151
+ return folder:FindFirstChild(itemId) ~= nil
152
+ end
153
+
154
+ function RemoteValidator.playerHasAttribute(player: Player, attribute: string, expectedValue: any?): boolean
155
+ local value = player:GetAttribute(attribute)
156
+ if expectedValue ~= nil then
157
+ return value == expectedValue
158
+ end
159
+ return value ~= nil
160
+ end
161
+
162
+ -------------------------------------------------------------------------------
163
+ -- Distance Check
164
+ -- Validates that two positions are within an acceptable range.
165
+ -------------------------------------------------------------------------------
166
+
167
+ function RemoteValidator.withinRange(posA: Vector3, posB: Vector3, maxDistance: number): boolean
168
+ return (posA - posB).Magnitude <= maxDistance
169
+ end
170
+
171
+ function RemoteValidator.playerWithinRange(player: Player, targetPos: Vector3, maxDistance: number): boolean
172
+ local character = player.Character
173
+ if not character then
174
+ return false
175
+ end
176
+
177
+ local root = character:FindFirstChild("HumanoidRootPart")
178
+ if not root then
179
+ return false
180
+ end
181
+
182
+ return RemoteValidator.withinRange(root.Position, targetPos, maxDistance)
183
+ end
184
+
185
+ -------------------------------------------------------------------------------
186
+ -- Cleanup — prevent memory leaks from departed players
187
+ -------------------------------------------------------------------------------
188
+
189
+ Players.PlayerRemoving:Connect(function(player)
190
+ RemoteValidator.clearPlayerCooldowns(player)
191
+ end)
192
+
193
+ return RemoteValidator
@@ -1,128 +1,128 @@
1
- ---
2
- name: roblox-publish-checklist
3
- description: "Pre-publish verification gauntlet for Roblox games"
4
- tags: [roblox, publish, checklist, verification]
5
- ---
6
-
7
- # /publish-checklist - Pre-Publish Verification
8
-
9
- You are verifying a Roblox game is ready to publish. Work through every category below. For each item, check it and note PASS/FAIL/SKIP with a brief explanation.
10
-
11
- ---
12
-
13
- ## 1. Data & Persistence
14
-
15
- - [ ] **DataStore save/load tested** - Player data saves on leave and loads on rejoin correctly
16
- - [ ] **Session locking verified** - Using ProfileStore or equivalent; no concurrent data corruption
17
- - [ ] **BindToClose implemented** - Server saves data before shutdown (game close, server hop)
18
- - [ ] **Data migration plan** - If updating an existing game, schema migration handles old data formats
19
- - [ ] **Edge case: disconnect during save** - Data not lost if player disconnects mid-save
20
- - [ ] **Edge case: multiple DataStore calls** - No race conditions from parallel saves
21
-
22
- ---
23
-
24
- ## 2. Security
25
-
26
- - [ ] **All remotes validated server-side** - Every RemoteEvent/RemoteFunction checks argument types, ranges, and ownership
27
- - [ ] **No sensitive data exposed** - ReplicatedStorage, StarterPlayer have no server-only logic or secrets
28
- - [ ] **Rate limiting on all remotes** - Per-player throttling prevents flooding/exploitation
29
- - [ ] **No client-trusted game logic** - Currency, inventory, damage, positions calculated server-side only
30
- - [ ] **ProcessReceipt handled correctly** - Grant item THEN return PurchaseGranted; NotProcessedYet on failure
31
- - [ ] **Anti-cheat basics** - Speed checks, teleport detection, inventory validation
32
-
33
- ---
34
-
35
- ## 3. Performance
36
-
37
- - [ ] **Mobile tested** - Game runs on mobile devices without crashes or severe lag
38
- - [ ] **Part count within limits** - Workspace part count reasonable for target devices
39
- - [ ] **No memory leaks** - Events disconnected on cleanup, no orphaned instances accumulating
40
- - [ ] **MicroProfiler reviewed** - No scripts consistently over budget (>1ms per frame)
41
- - [ ] **StreamingEnabled considered** - If large map, StreamingEnabled is enabled and tested
42
- - [ ] **Signal cleanup** - No undisconnected BindableEvent/RemoteEvent connections leaking
43
-
44
- ---
45
-
46
- ## 4. Monetization
47
-
48
- - [ ] **GamePasses work correctly** - Purchasing grants the correct benefit, idempotent on rejoin
49
- - [ ] **DevProducts grant properly** - Consumables delivered, ProcessReceipt handles edge cases
50
- - [ ] **Premium benefits functional** - Premium payout optimized, exclusive perks work
51
- - [ ] **Prices reviewed** - Competitive with similar games, clear value proposition
52
- - [ ] **No pay-to-win concerns** - Free players have reasonable experience
53
- - [ ] **Premium Payouts enabled** - Game is eligible and configured for Premium Payouts
54
-
55
- ---
56
-
57
- ## 5. Mobile Compatibility
58
-
59
- - [ ] **Touch controls work** - All interactions accessible via tap
60
- - [ ] **UI scales properly** - Using Scale not Offset for UI elements; tested on small screens
61
- - [ ] **ContextActionService for input** - Game actions bound properly for mobile
62
- - [ ] **Small screen tested** - UI doesn't overlap, buttons are tappable, text is readable
63
- - [ ] **Landscape and portrait** - Orientation handled if applicable
64
- - [ ] **Performance on low-end devices** - Tested on minimum spec mobile device
65
-
66
- ---
67
-
68
- ## 6. Gameplay
69
-
70
- - [ ] **Core loop tested end-to-end** - Play for 10+ minutes, full loop works
71
- - [ ] **Edge cases handled:**
72
- - [ ] Disconnect during trade/transaction
73
- - [ ] Death during cutscene
74
- - [ ] Player leaves during multiplayer event
75
- - [ ] Rapid button pressing
76
- - [ ] Backfill/rejoin during active game
77
- - [ ] **Tutorial/FTUE works** - New player can learn the game without confusion
78
- - [ ] **Difficulty curve** - Early game engaging, progression feels rewarding
79
- - [ ] **Fun check** - Core loop is actually enjoyable to play repeatedly
80
-
81
- ---
82
-
83
- ## 7. Metadata
84
-
85
- - [ ] **Game icon set** - 512x512, clear and representative
86
- - [ ] **Thumbnails uploaded** - At least 3 images showing gameplay
87
- - [ ] **Description written** - Clear, compelling, includes key features
88
- - [ ] **Genre selected** - Correct category for discovery
89
- - [ ] **Max players configured** - Appropriate for game type
90
- - [ ] **Game badges** - Achievement badges set up for milestones
91
- - [ ] **Game rating** - Age-appropriate settings configured
92
-
93
- ---
94
-
95
- ## 8. Social
96
-
97
- - [ ] **Private servers configured** - Available and priced if applicable
98
- - [ ] **Social features tested** - Party system, chat, friending all work
99
- - [ ] **Report/block doesn't break game** - Reporting a player doesn't crash or corrupt game state
100
- - [ ] **Server browser** - Game appears in search with correct tags
101
- - [ ] **Team play** - If multiplayer, team assignment and switching work
102
-
103
- ---
104
-
105
- ## 9. Analytics
106
-
107
- - [ ] **Key events instrumented:**
108
- - [ ] Player joins / leaves
109
- - [ ] Purchases (GamePass and DevProduct)
110
- - [ ] Level/zone completions
111
- - [ ] Session length tracking
112
- - [ ] Error/crash reporting
113
- - [ ] **Basic funnel tracking** - New player → tutorial complete → first purchase → retention
114
- - [ ] **Dashboard configured** - Analytics visible in Roblox Creator Dashboard
115
-
116
- ---
117
-
118
- ## Summary
119
-
120
- After checking all items, output:
121
-
122
- 1. **Overall status:** READY / NOT READY
123
- 2. **Critical blockers** (must fix before publish)
124
- 3. **Warnings** (should fix, not blocking)
125
- 4. **Passed items** - Count and percentage
126
- 5. **Failed items** - List each with the fix needed
127
-
1
+ ---
2
+ name: roblox-publish-checklist
3
+ description: "Pre-publish verification gauntlet for Roblox games"
4
+ tags: [roblox, publish, checklist, verification]
5
+ ---
6
+
7
+ # /publish-checklist - Pre-Publish Verification
8
+
9
+ You are verifying a Roblox game is ready to publish. Work through every category below. For each item, check it and note PASS/FAIL/SKIP with a brief explanation.
10
+
11
+ ---
12
+
13
+ ## 1. Data & Persistence
14
+
15
+ - [ ] **DataStore save/load tested** - Player data saves on leave and loads on rejoin correctly
16
+ - [ ] **Session locking verified** - Using ProfileStore or equivalent; no concurrent data corruption
17
+ - [ ] **BindToClose implemented** - Server saves data before shutdown (game close, server hop)
18
+ - [ ] **Data migration plan** - If updating an existing game, schema migration handles old data formats
19
+ - [ ] **Edge case: disconnect during save** - Data not lost if player disconnects mid-save
20
+ - [ ] **Edge case: multiple DataStore calls** - No race conditions from parallel saves
21
+
22
+ ---
23
+
24
+ ## 2. Security
25
+
26
+ - [ ] **All remotes validated server-side** - Every RemoteEvent/RemoteFunction checks argument types, ranges, and ownership
27
+ - [ ] **No sensitive data exposed** - ReplicatedStorage, StarterPlayer have no server-only logic or secrets
28
+ - [ ] **Rate limiting on all remotes** - Per-player throttling prevents flooding/exploitation
29
+ - [ ] **No client-trusted game logic** - Currency, inventory, damage, positions calculated server-side only
30
+ - [ ] **ProcessReceipt handled correctly** - Grant item THEN return PurchaseGranted; NotProcessedYet on failure
31
+ - [ ] **Anti-cheat basics** - Speed checks, teleport detection, inventory validation
32
+
33
+ ---
34
+
35
+ ## 3. Performance
36
+
37
+ - [ ] **Mobile tested** - Game runs on mobile devices without crashes or severe lag
38
+ - [ ] **Part count within limits** - Workspace part count reasonable for target devices
39
+ - [ ] **No memory leaks** - Events disconnected on cleanup, no orphaned instances accumulating
40
+ - [ ] **MicroProfiler reviewed** - No scripts consistently over budget (>1ms per frame)
41
+ - [ ] **StreamingEnabled considered** - If large map, StreamingEnabled is enabled and tested
42
+ - [ ] **Signal cleanup** - No undisconnected BindableEvent/RemoteEvent connections leaking
43
+
44
+ ---
45
+
46
+ ## 4. Monetization
47
+
48
+ - [ ] **GamePasses work correctly** - Purchasing grants the correct benefit, idempotent on rejoin
49
+ - [ ] **DevProducts grant properly** - Consumables delivered, ProcessReceipt handles edge cases
50
+ - [ ] **Premium benefits functional** - Premium payout optimized, exclusive perks work
51
+ - [ ] **Prices reviewed** - Competitive with similar games, clear value proposition
52
+ - [ ] **No pay-to-win concerns** - Free players have reasonable experience
53
+ - [ ] **Premium Payouts enabled** - Game is eligible and configured for Premium Payouts
54
+
55
+ ---
56
+
57
+ ## 5. Mobile Compatibility
58
+
59
+ - [ ] **Touch controls work** - All interactions accessible via tap
60
+ - [ ] **UI scales properly** - Using Scale not Offset for UI elements; tested on small screens
61
+ - [ ] **ContextActionService for input** - Game actions bound properly for mobile
62
+ - [ ] **Small screen tested** - UI doesn't overlap, buttons are tappable, text is readable
63
+ - [ ] **Landscape and portrait** - Orientation handled if applicable
64
+ - [ ] **Performance on low-end devices** - Tested on minimum spec mobile device
65
+
66
+ ---
67
+
68
+ ## 6. Gameplay
69
+
70
+ - [ ] **Core loop tested end-to-end** - Play for 10+ minutes, full loop works
71
+ - [ ] **Edge cases handled:**
72
+ - [ ] Disconnect during trade/transaction
73
+ - [ ] Death during cutscene
74
+ - [ ] Player leaves during multiplayer event
75
+ - [ ] Rapid button pressing
76
+ - [ ] Backfill/rejoin during active game
77
+ - [ ] **Tutorial/FTUE works** - New player can learn the game without confusion
78
+ - [ ] **Difficulty curve** - Early game engaging, progression feels rewarding
79
+ - [ ] **Fun check** - Core loop is actually enjoyable to play repeatedly
80
+
81
+ ---
82
+
83
+ ## 7. Metadata
84
+
85
+ - [ ] **Game icon set** - 512x512, clear and representative
86
+ - [ ] **Thumbnails uploaded** - At least 3 images showing gameplay
87
+ - [ ] **Description written** - Clear, compelling, includes key features
88
+ - [ ] **Genre selected** - Correct category for discovery
89
+ - [ ] **Max players configured** - Appropriate for game type
90
+ - [ ] **Game badges** - Achievement badges set up for milestones
91
+ - [ ] **Game rating** - Age-appropriate settings configured
92
+
93
+ ---
94
+
95
+ ## 8. Social
96
+
97
+ - [ ] **Private servers configured** - Available and priced if applicable
98
+ - [ ] **Social features tested** - Party system, chat, friending all work
99
+ - [ ] **Report/block doesn't break game** - Reporting a player doesn't crash or corrupt game state
100
+ - [ ] **Server browser** - Game appears in search with correct tags
101
+ - [ ] **Team play** - If multiplayer, team assignment and switching work
102
+
103
+ ---
104
+
105
+ ## 9. Analytics
106
+
107
+ - [ ] **Key events instrumented:**
108
+ - [ ] Player joins / leaves
109
+ - [ ] Purchases (GamePass and DevProduct)
110
+ - [ ] Level/zone completions
111
+ - [ ] Session length tracking
112
+ - [ ] Error/crash reporting
113
+ - [ ] **Basic funnel tracking** - New player → tutorial complete → first purchase → retention
114
+ - [ ] **Dashboard configured** - Analytics visible in Roblox Creator Dashboard
115
+
116
+ ---
117
+
118
+ ## Summary
119
+
120
+ After checking all items, output:
121
+
122
+ 1. **Overall status:** READY / NOT READY
123
+ 2. **Critical blockers** (must fix before publish)
124
+ 3. **Warnings** (should fix, not blocking)
125
+ 4. **Passed items** - Count and percentage
126
+ 5. **Failed items** - List each with the fix needed
127
+
128
128
  If NOT READY, provide specific fixes for every failed item before the user publishes.