Skip to content

fix(core): convert AsyncOperation to UniTask for Unity 6 compatibility#593

Closed
JasonXuDeveloper wants to merge 9 commits intomasterfrom
fix/unity6-asyncoperation-await
Closed

fix(core): convert AsyncOperation to UniTask for Unity 6 compatibility#593
JasonXuDeveloper wants to merge 9 commits intomasterfrom
fix/unity6-asyncoperation-await

Conversation

@JasonXuDeveloper
Copy link
Copy Markdown
Owner

Summary

  • Fix CS0311 compilation error in Unity 6 where UnityEngine.AsyncOperation cannot be directly awaited
  • Convert SceneManager.LoadSceneAsync() to use .ToUniTask() extension method

Problem

In Unity 6, UnityEngine.AsyncOperation cannot be used as a type parameter for EnumeratorAsyncExtensions.GetAwaiter<T>() because there's no implicit reference conversion to System.Collections.IEnumerator.

Solution

Use the ToUniTask() extension method from Cysharp.Threading.Tasks to convert the AsyncOperation to a UniTask, which can be awaited. This pattern is already used elsewhere in the codebase (e.g., line 145 in the same file).

Test plan

  • Open the project in Unity 6
  • Verify no CS0311 compilation errors
  • Test scene loading error path to ensure fallback scene loads correctly

🤖 Generated with Claude Code

JasonXuDeveloper and others added 9 commits January 28, 2026 22:58
Major UI overhaul implementing shadcn-inspired design with glassmorphic
elements in dark mode and clean monochromatic styling in light mode.

## New UI Package (com.jasonxudeveloper.jengine.ui)

### Components
- **Button**: JButton, JToggleButton, JButtonGroup with 5 variants
- **Form**: JFormField, JTextField, JDropdown, JToggle, JObjectField
- **Layout**: JCard, JSection, JStack, JRow for composition
- **Feedback**: JStatusBar, JLogView, JProgressBar
- **Navigation**: JBreadcrumb with clean hierarchical display

### Theme System
- Design tokens (Tokens.cs) with dark/light theme support
- Glassmorphic palette for dark mode (translucent layers, vibrant accents)
- shadcn-style monochromatic palette for light mode (black/white/grey only)
- 8px spacing grid, typography scale, border radius system
- Smooth transitions (150-300ms)

### Enhanced Editor UIs
- BootstrapEditorUI: Redesigned Bootstrap inspector with modern components
- PanelUI: Redesigned Panel window with enhanced scene management

## Core Package Improvements

### Code Deduplication
- **EditorUtils.cs**: Extracted 6 shared helper methods from BootstrapEditor
  and BootstrapEditorUI (GetAvailableAsmdefFiles, GetAvailableHotScenes,
  GetAvailableHotClasses, GetAvailableHotMethods,
  GetAvailableDynamicSecretKeys, GetAvailableAOTDataFiles)
- **BuildHelper.cs**: New shared build execution logic with UI callbacks,
  eliminating ~200 lines of duplication between Panel.cs and PanelUI.cs

### Bug Fixes
- Panel.cs: Added null checks in LogMessage to prevent crashes when using
  enhanced PanelUI
- PanelUI: Creates its own BuildManager with proper log routing to JLogView

## Design Decisions

### Light Theme Philosophy
- Monochromatic black/white/grey only (no colors except semantic highlights)
- Buttons use grey shades (Primary: gray-700, Secondary: gray-300)
- Clean, minimal aesthetic inspired by shadcn/ui

### Dark Theme Philosophy
- Glassmorphic translucent layers (40-80% opacity)
- Vibrant cyan accents (#06B6D4) with subtle glow effects
- 5-level glass system (Base → Subtle → Surface → Elevated → Overlay)

### Component Patterns
- Fluent API for chaining (.WithText().FullWidth())
- Consistent spacing and sizing across all components
- Theme-aware colors (automatically adapt to Unity editor theme)
- Proper keyboard navigation with visible focus states

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: JasonXuDeveloper - 傑 <jason@xgamedev.net>
Replace lambda closures with static lambdas and state parameters to avoid
heap allocations in RegisterCallback calls. Updated 6 component files:

- JBreadcrumb: static methods with state parameters
- JCard: instance methods
- JStack: static lambda with tuple state
- JToggle: static lambdas with state parameters
- JObjectField: instance methods + static lambdas with state
- JTextField: static lambdas with state parameters

This improves performance by eliminating 14 closure allocations across
the UI toolkit components using C#9 static lambda support.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: JasonXuDeveloper - 傑 <jason@xgamedev.net>
Replace vibrant glassmorphic design with clean monochrome palette where
dark theme is the grayscale inversion of light theme.

Changes:
- Remove all vibrant accent colors (cyan, emerald, rose, amber)
- Dark theme now uses black/white/greys inverted from light theme
- Light theme colors remain unchanged
- Remove opacity-based glass layers, use solid greys
- Update JToggle to use Primary/Secondary instead of Accent
- Simplify comments to reflect new monochrome approach

Color mapping (dark theme inverted from light):
- BgBase: #0F1419 (near-black) ← #FFFFFF (white)
- BgSurface: #374151 (gray-700) ← #E5E7EB (gray-200)
- TextPrimary: #FFFFFF (white) ← #111827 (gray-900)
- Primary: #D1D5DB (gray-300) ← #374151 (gray-700)
- Borders: #4B5563 (gray-600) ← #D1D5DB (gray-300)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: JasonXuDeveloper - 傑 <jason@xgamedev.net>
Improved dark theme to use truly neutral RGB greys (R=G=B) instead of
blue-tinted colors. Fixed three visual issues from user feedback:

1. Primary button color too dark - changed dark theme to use lighter
   #C8C8C8 grey for better contrast with white text
2. Status bar showing blue - removed colored backgrounds in dark mode,
   now uses neutral grey like light mode (monochrome design)
3. Log view too black - changed from BgBase (#0A0A0A) to BgSubtle
   (#1A1A1A) for slightly lighter background

Color changes (dark theme only, light theme unchanged):
- BgBase: #0F1419 → #0A0A0A (pure neutral black)
- BgSubtle: #1F2937 → #1A1A1A (pure neutral dark grey)
- BgSurface: #374151 → #2A2A2A (pure neutral grey)
- BgElevated: #4B5563 → #3A3A3A (pure neutral medium-dark grey)
- BgOverlay: #6B7280 → #4A4A4A (pure neutral medium grey)
- Primary: #D1D5DB → #C8C8C8 (lighter for better button contrast)
- All text/borders now use neutral greys (#FFFFFF, #D0D0D0, etc.)

JStatusBar now uses monochrome design in both themes (no colored
backgrounds in dark mode).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: JasonXuDeveloper - 傑 <jason@xgamedev.net>
…trast

Fixed multiple visual issues in dark theme based on user feedback:

1. Button colors now properly inverted:
   - Dark Primary (#D0D0D0) = Light Secondary
   - Dark Secondary (#374151) = Light Primary
   - True grayscale inversion between themes

2. Input field backgrounds differentiated:
   - New BgInput color (#353535) lighter than BgSurface in dark mode
   - Applies to JTextField, JObjectField, and JDropdown
   - Better visual separation from surrounding surface

3. Toggle styling fixed:
   - Track colors match Primary/Secondary button colors
   - Thumb stays white in both themes (no inversion)

4. Separator/divisor visibility improved:
   - BorderSubtle lightened to #454545 in dark mode
   - Now visible against darker backgrounds

5. Button text colors use theme tokens:
   - JButton and JToggleButton use PrimaryText/SecondaryText
   - No more hardcoded Color.white
   - Dark Primary buttons now have black text (#111111)

6. Log view lightened:
   - Uses BgSubtle (#252525) instead of BgBase
   - More readable background

Color mapping (dark theme):
- Primary: #D0D0D0 (light grey, black text)
- Secondary: #374151 (dark grey, white text)
- BgInput: #353535 (for inputs)
- BgSubtle: #252525 (for log view)
- BorderSubtle: #454545 (for separators)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: JasonXuDeveloper - 傑 <jason@xgamedev.net>
Fixed Primary button hover and active states to properly invert with light
theme's Secondary colors:

Dark mode Primary (was wrong):
- Hover: #E0E0E0 → #9A9A9A (now matches light's SecondaryHover)
- Active: #C0C0C0 → #6A6A6A (now matches light's SecondaryActive)

Now the inversion is complete and consistent across all button states.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: JasonXuDeveloper - 傑 <jason@xgamedev.net>
Replace LINQ Any() with Count > 0 or Length > 0 for better
performance as recommended by CodeFactor (CA1860).

Also remove duplicate blank line (SA1507).

Signed-off-by: JasonXuDeveloper - 傑 <jason@xgamedev.net>
- Add XML documentation to Tokens.cs nested class members
- Update code review instructions to document LINQ avoidance pattern
  for performance (use inline null checks instead of .Where())

Signed-off-by: JasonXuDeveloper - 傑 <jason@xgamedev.net>
In Unity 6, UnityEngine.AsyncOperation cannot be directly awaited.
Convert to UniTask using .ToUniTask() extension method.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: JasonXuDeveloper - 傑 <jason@xgamedev.net>
Copilot AI review requested due to automatic review settings January 28, 2026 22:36
@github-actions github-actions bot added documentation Improvements or additions to documentation core editor labels Jan 28, 2026
@JasonXuDeveloper JasonXuDeveloper deleted the fix/unity6-asyncoperation-await branch January 28, 2026 22:38
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

This pull request fixes a Unity 6 compilation error and adds a comprehensive new UI package for JEngine editor windows. The main change converts SceneManager.LoadSceneAsync() to use .ToUniTask() for Unity 6 compatibility. The bulk of the PR introduces the com.jasonxudeveloper.jengine.ui package with themed UI components, utilities, and styling for editor interfaces.

Changes:

  • Fixed Unity 6 CS0311 compilation error by converting AsyncOperation to UniTask
  • Added new JEngine UI package with comprehensive component library (buttons, forms, layouts, feedback)
  • Refactored Panel and BootstrapEditor to support pluggable UI handlers
  • Moved utility methods to EditorUtils and created BuildHelper for code reuse
  • Updated editor labels to be more concise

Reviewed changes

Copilot reviewed 80 out of 80 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
Bootstrap.Common.cs Fixed Unity 6 compatibility by adding .ToUniTask() to AsyncOperation
EditorUtils.cs Added helper methods for dropdown population and asset queries
Panel.cs Added handler registration for pluggable UI, refactored build methods
BootstrapEditor.cs Added handler registration, moved utility methods to EditorUtils
BuildHelper.cs New helper class for build operations with UI callbacks
SettingsUIBuilder.cs Updated labels to be more concise
JEngine.UI package New comprehensive UI component library with theming, components, and utilities
code-review.instructions.md Added performance guideline about avoiding LINQ in hot paths

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

Comment on lines +154 to +159
return assembly.GetTypes()
.Where(t => t.IsClass && t.IsPublic)
.Where(t => t.GetMethods(BindingFlags.Public | BindingFlags.Static).Length > 0)
.Select(t => t.FullName)
.OrderBy(n => n)
.ToList();
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

LINQ usage in editor utility code violates performance guideline. Multiple LINQ operations (Where, Select, OrderBy) create iterator and delegate allocations. Replace with a simple foreach loop that filters and sorts manually.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +195 to +202
return type.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(m => m.ReturnType == typeof(void) ||
m.ReturnType == typeof(UniTask) ||
m.ReturnType == typeof(System.Threading.Tasks.Task))
.Where(m => m.GetParameters().Length == 0)
.Select(m => m.Name)
.OrderBy(n => n)
.ToList();
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

LINQ usage in editor utility code violates performance guideline. Multiple LINQ operations (Where, Select, OrderBy) create iterator and delegate allocations. Replace with a foreach loop that filters, collects, and sorts method names manually.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +222 to +226
var secretKeyFiles = bytesGuids
.Select(AssetDatabase.GUIDToAssetPath)
.Where(path => path.EndsWith(".bytes") &&
(path.Contains("Secret") || path.Contains("Obfuz") || path.Contains("Key")))
.ToList();
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

LINQ usage in editor utility code violates performance guideline. Multiple LINQ operations (Select, Where) create iterator and delegate allocations. Replace with a foreach loop that checks the condition and adds to the result list.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +246 to +251
var aotDataGuids = AssetDatabase.FindAssets("t:TextAsset", new[] { "Assets/HotUpdate/Compiled" });
return aotDataGuids
.Select(AssetDatabase.GUIDToAssetPath)
.Where(path => path.EndsWith(".bytes"))
.OrderBy(path => path)
.ToList();
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

LINQ usage in editor utility code violates performance guideline. Multiple LINQ operations (Select, Where, OrderBy) create iterator and delegate allocations. Replace with a foreach loop that checks the condition, adds to a list, and sorts manually.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +122 to +126
return asmdefGuids
.Select(AssetDatabase.GUIDToAssetPath)
.Select(System.IO.Path.GetFileNameWithoutExtension)
.Select(asmdefName => asmdefName + ".dll")
.ToList();
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

LINQ usage in editor utility code violates performance guideline. This code is called when populating dropdowns in the editor UI, which is a hot path during UI updates. Replace LINQ chain with a simple foreach loop to avoid iterator and delegate allocations.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +46 to +58
foreach (var button in buttons)
{
if (button != null)
{
// Apply group styling to buttons - compact
button.style.marginRight = Tokens.Spacing.Sm;
button.style.marginBottom = Tokens.Spacing.Xs;
button.style.flexGrow = 1;
button.style.flexShrink = 0;
button.style.minWidth = 100;
base.Add(button);
}
}
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

This foreach loop implicitly filters its target sequence - consider filtering the sequence explicitly using '.Where(...)'.

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +83
foreach (var button in buttons)
{
if (button != null)
{
button.style.marginRight = Tokens.Spacing.Sm;
button.style.marginBottom = Tokens.Spacing.Xs;
button.style.flexGrow = 1;
button.style.flexShrink = 0;
button.style.minWidth = 100;
base.Add(button);
}
}
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

This foreach loop implicitly filters its target sequence - consider filtering the sequence explicitly using '.Where(...)'.

Copilot uses AI. Check for mistakes.
Comment on lines +105 to +111
foreach (var child in children)
{
if (child != null)
{
_fields.Add(child);
}
}
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

This foreach loop implicitly filters its target sequence - consider filtering the sequence explicitly using '.Where(...)'.

Copilot uses AI. Check for mistakes.
Comment on lines +149 to +155
foreach (var child in children)
{
if (child != null)
{
_controlContainer.Add(child);
}
}
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

This foreach loop implicitly filters its target sequence - consider filtering the sequence explicitly using '.Where(...)'.

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +98
foreach (var child in children)
{
if (child != null)
{
_content.Add(child);
}
}
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

This foreach loop implicitly filters its target sequence - consider filtering the sequence explicitly using '.Where(...)'.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown

Unity Test Results

EditMode: All tests passed
PlayMode: All tests passed

Unity Version: 2022.3.55f1
Project Path: UnityProject

✅ All tests passed! The PR is ready for review.

View workflow run

Click here to view the full workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core documentation Improvements or additions to documentation editor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants