ok-oldking / ok-oldking/ok-script

Fix one-time task re-run delay before run when the target window is unfocused

Open
#94 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
739
Forks
208
Avg merge
7h 47m
Merged PRs (30d)
1

Description

Context

This issue was found while developing and repeatedly debugging the FishingOnceTask in ok-how-to-fish. ok-how-to-fish was created from the ok-script application template and uses ok-script as its underlying task execution framework.

The task uses the documented BaseTask API. Its run() method starts by calling ensure_in_front() before sending keyboard and mouse input. The expected debugging workflow is to run the task, adjust the task code or configuration, then run the same task again.

This is not caused by the application template using the task API incorrectly or by the GUI debug action calling the task incorrectly. The GUI run action calls StartController.start(task), which is the framework's normal entry point for starting a one-time task.

Reproduction

  1. On Windows, configure a game with a foreground interaction backend such as Pynput or PyDirect.
  2. Register a one-time task whose run() starts with ensure_in_front() and then performs input. The FishingOnceTask in ok-how-to-fish is an example.
  3. Start the task once while the game window is active. The task runs successfully.
  4. Let the client UI or another application take focus.
  5. Start the same one-time task again, for example from the GUI task card or the task editor's Run action.

Expected behavior

The target game window is brought to the foreground before the executor requests the first frame, and the task enters task.run() normally on every run.

Actual behavior

The task is queued and selected, but it does not reach its first task-level action immediately. For example, the log does not show the FishingOnceTask state Selecting rod until after the frame wait/timeout.

The current execution order is effectively:

select one-time task
-> request next_frame()
-> task.run()

For foreground interaction backends, should_capture() returns False while the target window is not active. Therefore next_frame() waits before task.run() is reached. The task-level ensure_in_front() cannot prepare the window because it is after the blocked operation. In the current executor, the one-time path passes time_out=4, so this appears as an avoidable delay of up to about four seconds rather than a true infinite wait.

There is another relevant framework path: StartController._mark_task_enabled() directly marks the task enabled and queues it. It does not go through BaseTask.enable(), where interaction.on_run() is otherwise called. This path is used by the GUI task card/editor flow and also by command-line/headless and Web/API task starts.

Root cause

The framework prepares the foreground interaction too late for one-time tasks. A one-time task must be prepared after it is selected but before the first next_frame() call.

The task API usage is valid: ensure_in_front() is a reasonable task-level action, but the executor's precondition that it must obtain a frame first makes that action unable to help in this case.

Trigger tasks should keep their existing behavior because they are expected to observe the current foreground/capture state rather than forcibly foregrounding the target for every trigger check.

Proposed fix

Prepare the interaction backend before the first frame for one-time tasks. The follow-up PR implements this at the TaskExecutor boundary and adds a regression test for the execution order. The preparation is a no-op for interaction backends that do not need foreground activation.

Environment

  • Windows 11
  • ok-script 2.0.0b7
  • Python 3.12
  • Pynput interaction backend
  • Reproduced while developing ok-how-to-fish

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the TaskExecutor boundary and trace the one-time execution path from StartController.start(task), including _mark_task_enabled(), BaseTask.enable(), and the first next_frame() call. Check the follow-up regression test for the expected ordering, and consider the issue complete when one-time tasks prepare the interaction before their first frame while trigger tasks retain their existing behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.