Skip to content

Treat Folia global tick thread as main thread to fix QueueHandler scheduling errors#6

Merged
Chwitst187 merged 1 commit intomainfrom
codex/fix-thread-error-in-fastasyncworldedit
Feb 25, 2026
Merged

Treat Folia global tick thread as main thread to fix QueueHandler scheduling errors#6
Chwitst187 merged 1 commit intomainfrom
codex/fix-thread-error-in-fastasyncworldedit

Conversation

@Chwitst187
Copy link
Copy Markdown
Owner

Motivation

  • QueueHandler was throwing IllegalStateException: Not main thread when run from Folia's global region scheduler because Fawe.isMainThread() only checked the bootstrap thread.
  • The platform needs an extendable way to determine whether the current execution context should be treated as a synchronous/main thread so Folia and legacy Bukkit both work.

Description

  • Added a platform contract TaskManager#isMainThread() to allow platform-specific main-thread detection (file: worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TaskManager.java).
  • Updated Fawe.isMainThread() to prefer the active TaskManager implementation for thread detection and fall back to the legacy bootstrap-thread check (file: worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java).
  • Implemented BukkitTaskManager.isMainThread() to return true when either Bukkit.isPrimaryThread() is true or when running on Folia's global tick thread via reflective Bukkit.isGlobalTickThread() detection, and added the helper isFoliaGlobalTickThread() (file: worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/BukkitTaskManager.java).

Testing

  • Attempted to compile the relevant modules with ./gradlew :worldedit-bukkit:compileJava :worldedit-core:compileJava --no-daemon, which reached configuration and compilation steps but failed due to an unrelated multi-project configuration error (Task with name 'build' not found in project ':worldedit-libs:cli'), so no full build artifacts or unit tests were produced in this environment.
  • Performed local code inspection and searches to verify new API usage sites and ensure the new isMainThread() hook can be implemented by platforms; no runtime tests were run here.

Codex Task

Copilot AI review requested due to automatic review settings February 25, 2026 20:24
@Chwitst187 Chwitst187 merged commit 7b6a69e into main Feb 25, 2026
1 check passed
@Chwitst187 Chwitst187 deleted the codex/fix-thread-error-in-fastasyncworldedit branch February 25, 2026 20:24
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a platform-level “main thread” contract so FAWE can treat Folia’s global tick thread as synchronous, avoiding IllegalStateException: Not main thread when QueueHandler runs under Folia scheduling.

Changes:

  • Introduces TaskManager#isMainThread() as a platform-specific main-thread detection hook.
  • Updates Fawe.isMainThread() to prefer the active TaskManager implementation for thread detection.
  • Implements Bukkit/Folia-aware main-thread detection in BukkitTaskManager (primary thread or Folia global tick thread via reflection).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TaskManager.java Adds the new isMainThread() platform contract to TaskManager.
worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java Routes Fawe.isMainThread() through the platform TaskManager when available.
worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/BukkitTaskManager.java Implements Bukkit + Folia global tick thread detection for “main thread” semantics.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +233 to +239
private boolean isFoliaGlobalTickThread() {
try {
Method method = Bukkit.class.getMethod("isGlobalTickThread");
return Boolean.TRUE.equals(method.invoke(null));
} catch (ReflectiveOperationException ignored) {
return false;
}
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isFoliaGlobalTickThread() does reflective method lookup on every call and, on non-Folia servers, will throw/catch NoSuchMethodException each time isMainThread() is evaluated off the primary thread. This can become a significant hot-path cost. Cache the presence of Bukkit.isGlobalTickThread() (e.g., resolve the Method once into a static final/lazy field and short-circuit to false when absent) and avoid using exceptions for control flow in the common (non-Folia) case.

Copilot uses AI. Check for mistakes.
Comment on lines +213 to +217
TaskManager taskManager = TaskManager.IMP;
if (taskManager != null) {
return taskManager.isMainThread();
}
return instance.thread == Thread.currentThread();
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fawe.isMainThread() is using the deprecated TaskManager.IMP field. This can bypass platform-specific thread detection if IMP is unset while TaskManager.INSTANCE exists, and it also adds new usage of an API marked for removal. Prefer calling TaskManager.taskManager().isMainThread() here (or otherwise retrieving the active TaskManager via the non-deprecated path) and keeping the legacy instance.thread comparison as the fallback if needed.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants