@el4cteo/rbx-studio-mcp 0.6.8 → 0.7.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.
@@ -305,7 +305,11 @@ function Exec.run(params: { [string]: any }): { [string]: any }
305
305
 
306
306
  local returned: { any } = {}
307
307
  for index = 2, math.min(results.n, MAX_RETURN_VALUES + 1) do
308
- table.insert(returned, describe(results[index]))
308
+ -- A nil return is written out rather than dropped. `table.insert` of nil
309
+ -- does nothing, so `return a, nil, b` came back as two values and every
310
+ -- one after the nil shifted into the wrong position.
311
+ local value = results[index]
312
+ table.insert(returned, if value == nil then "nil" else describe(value))
309
313
  end
310
314
 
311
315
  return {
@@ -301,18 +301,42 @@ end
301
301
 
302
302
  makeCursor()
303
303
 
304
- for _, step in plan do
304
+ --[[
305
+ Some keys cannot be sent at all. Roblox keeps them for its own menus --
306
+ Escape, Tab, F9, and in this place's case also One -- and `SendKey` THROWS
307
+ for them ("permanently bound to a CoreGUI core action"). Uncaught, that
308
+ killed this script mid-plan: the rest of the steps never ran, nothing was
309
+ reported, and the tool gave up with NO_ACK after its full timeout while the
310
+ error sat in Studio's Output. Which keys are reserved depends on the place
311
+ (One is the backpack hotbar), so it is caught here rather than listed.
312
+ ]]
313
+ local function refusedKey(key, err)
314
+ local message = tostring(err)
315
+ if string.find(message, "CoreGUI", 1, true) then
316
+ return string.format(
317
+ "%s was not sent: Roblox reserves it for its own menus, so no script can press it. "
318
+ .. "Test what the game does on that key by calling its handler another way.",
319
+ key
320
+ )
321
+ end
322
+ return string.format("%s was not sent: %s", key, message)
323
+ end
324
+
325
+ local function runStep(step): boolean
305
326
  local kind = step.kind
306
327
  if kind == "key" then
307
328
  local code = Enum.KeyCode[step.key]
308
- if step.action == "release" then
329
+ local down = step.action ~= "release"
330
+ local sent, err = pcall(function()
331
+ virtual:SendKey(down, code, false)
332
+ end)
333
+ if not sent then
334
+ table.insert(notes, refusedKey(step.key, err))
335
+ return false
336
+ end
337
+ if down and step.action ~= "press" then
338
+ task.wait(step.hold or 0.08)
309
339
  virtual:SendKey(false, code, false)
310
- else
311
- virtual:SendKey(true, code, false)
312
- if step.action ~= "press" then
313
- task.wait(step.hold or 0.08)
314
- virtual:SendKey(false, code, false)
315
- end
316
340
  end
317
341
  elseif kind == "move" then
318
342
  moveCursor(step.x, step.y, 0.3)
@@ -364,7 +388,17 @@ for _, step in plan do
364
388
  virtual:SendTextInput(step.text)
365
389
  end
366
390
  end
367
- table.insert(performed, kind)
391
+ return true
392
+ end
393
+
394
+ for index, step in plan do
395
+ -- Guarded so one failing step can never stop the report going back.
396
+ local ok, done = pcall(runStep, step)
397
+ if not ok then
398
+ table.insert(notes, string.format("step %d (%s) failed: %s", index - 1, tostring(step.kind), tostring(done)))
399
+ elseif done then
400
+ table.insert(performed, step.kind)
401
+ end
368
402
  if step.after ~= nil and step.after > 0 then
369
403
  task.wait(step.after)
370
404
  end