Skip to content

feature: export Runtime to Distribution#27

Open
sheazywi wants to merge 2 commits into
devfrom
feature/runtime-export
Open

feature: export Runtime to Distribution#27
sheazywi wants to merge 2 commits into
devfrom
feature/runtime-export

Conversation

@sheazywi
Copy link
Copy Markdown
Member

@sheazywi sheazywi commented May 24, 2026

This pull request introduces several new features and improvements across the project, most notably the implementation of a "Runtime Export" workflow in the Editor, enhancements to project and asset serialization. The changes are grouped below by theme.

Editor: Runtime Export Workflow

  • Added a comprehensive "Export Runtime" feature to the Editor, enabling users to export a standalone runtime build of their project, including assets, runtime executable, dependencies, and resources. This includes utility functions for file/directory operations, build name sanitization, and locating the runtime executable. The export option is now available in the Editor's file menu. (EditorLayer.cpp, EditorLayer.h) [1] [2] [3] [4]
  • Added new dependencies and includes to support export logic. (EditorLayer.cpp) [1] [2]

Project & Asset Serialization

  • Implemented Project::LoadRuntime for loading runtime project configurations and asset packs, and improved initialization logic for project directories, file paths, and audio engine state during runtime project loading. (Project.cpp, Project.h) [1] [2] [3]

Project and Scene Configuration Tweaks

  • Updated the default project and scene settings to improve rendering quality and performance, including new rendering and shadow options, AO and SSR tweaks, and updated start scene. (Sandbox.luxproj, NewSceneSystem.luxscene) [1] [2] [3]
  • Changed the Editor application name to "Lux Editor". (LuxEditorApp.cpp)

Summary by CodeRabbit

  • New Features

    • Added runtime export functionality to build standalone executable versions of projects from the editor.
    • Added runtime project loading capabilities for deployed applications.
  • Improvements

    • Enhanced framebuffer handling for improved swapchain target support.
    • Updated scene renderer settings including shadow parameters (distance, resolution tier, and fade/range tuning).
    • Refined startup scene selection with improved UI workflow.
    • Enhanced scripting engine shutdown safety with null-pointer guards.
  • Chores

    • Updated build system to include runtime application project.
    • Removed legacy sandbox demo project from build configuration.
    • Removed redundant shader include files; updated shader system organization.

Review Change Stack

sheazywi added 2 commits May 24, 2026 00:37
 - For compilation, will use Lux-Runtime to Run and distribute games
 - Added File > Export Runtime... in the editor
 - Added swapchain-target framebuffer support for runtime final output
 - Deleted the root Sandbox project.
 - Cleaned lingering repo references: Linux build no longer tries to build removed Sandbox, README now mentions Lux-Runtime.
 - Added script shutdown guards so early runtime startup failures do not crash during app teardown.
 - use the same technique as the font, texture, mesh and envmap to get a startup scene
 - also correctly gets the exe from the
 - switch to single threaded to start up the window (Temp)
@sheazywi sheazywi self-assigned this May 24, 2026
Copilot AI review requested due to automatic review settings May 24, 2026 05:07
@sheazywi sheazywi added the enhancement New feature or request label May 24, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 24, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 09aad296-709a-4672-8acc-a7a7c84e60d8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/runtime-export

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sheazywi
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 24, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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 “Runtime Export” pipeline to package a project into a distributable runtime build, alongside a new Lux-Runtime executable and supporting runtime project/asset serialization changes.

Changes:

  • Editor: new “Export Runtime…” workflow that builds an asset pack, writes a Project.luxruntime, and copies runtime/resources into an export directory.
  • Core: adds runtime project loading (Project::LoadRuntime) and runtime project serialization (SerializeRuntime/DeserializeRuntime).
  • Runtime: introduces the Lux-Runtime app that loads an exported project + asset pack and presents via a swapchain-target framebuffer.

Reviewed changes

Copilot reviewed 89 out of 151 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
premake5.lua Adds Lux-Runtime to the workspace under a new “Runtime” group.
scripts/Linux-Build.sh Removes Sandbox build steps from the Linux build script.
README.md Updates setup/docs to include Lux-Runtime project generation.
.gitignore Ignores runtime pack artifacts (e.g., *.lap).
Editor/Source/EditorLayer.h Declares the new ExportRuntime() entry point.
Editor/Source/EditorLayer.cpp Implements export helpers + the runtime export workflow and menu integration.
Editor/Source/LuxEditorApp.cpp Renames the Editor app name string to “Lux Editor”.
Editor/SandboxProject/Sandbox.luxproj Updates default project configuration/settings used by the sample project.
Editor/SandboxProject/Assets/Scenes/NewSceneSystem.luxscene Updates the sample project’s scene configuration/content.
Core/Source/Lux/Project/Project.h Adds runtime-loading API surface (LoadRuntime) and related runtime activation hooks.
Core/Source/Lux/Project/Project.cpp Implements Project::LoadRuntime and updates runtime activation behavior.
Core/Source/Lux/Project/ProjectSerializer.h Exposes runtime project serialization/deserialization API.
Core/Source/Lux/Project/ProjectSerializer.cpp Implements runtime project binary format and YAML overrides.
Core/Source/Lux/Renderer/Framebuffer.h Adjusts framebuffer API to support swapchain-target framebuffers.
Core/Source/Lux/Renderer/Framebuffer.cpp Implements swapchain-target handle/size behavior used by the runtime presentation path.
Core/Source/Lux/Scripting/ScriptEngine.h Declares updated shutdown helpers for Mono lifecycle.
Core/Source/Lux/Scripting/ScriptEngine.cpp Adds safety guards in shutdown paths (null checks for Mono/domain state).
Lux-Runtime/premake5.lua Defines the new runtime target (platform filters, postbuild deps, etc.).
Lux-Runtime/Lux-Runtime.rc Adds Windows resources for the runtime application (icon/version resources).
Lux-Runtime/resource.h Declares Windows resource IDs for the runtime application.
Lux-Runtime/src/RuntimeApplication.cpp Adds runtime app entry point + CLI parsing (-C, --project).
Lux-Runtime/src/RuntimeLayer.h Declares runtime layer responsible for loading and presenting an exported project.
Lux-Runtime/src/RuntimeLayer.cpp Implements runtime project resolution, load, scene start, overlay, and swapchain submission.
Sandbox/Source/SandboxApp.cpp Removes legacy Sandbox application entry point (deleted).
Sandbox/Source/Sandbox2D.h Removes legacy Sandbox layer header (deleted).
Sandbox/Resources/Shaders/Wireframe.glsl Removes legacy Sandbox shader (deleted).
Sandbox/Resources/Shaders/Wireframe_Anim.glsl Removes legacy Sandbox shader (deleted).
Sandbox/Resources/Shaders/TexturePass.glsl Removes legacy Sandbox shader (deleted).
Sandbox/Resources/Shaders/SpotShadowMap.glsl Removes legacy Sandbox shader (deleted).
Sandbox/Resources/Shaders/SpotShadowMap_Anim.glsl Removes legacy Sandbox shader (deleted).
Sandbox/Resources/Shaders/Skybox.glsl Removes legacy Sandbox shader (deleted).
Sandbox/Resources/Shaders/shader.glsl Removes legacy Sandbox shader (deleted).
Sandbox/Resources/Shaders/SelectedGeometry.glsl Removes legacy Sandbox shader (deleted).
Sandbox/Resources/Shaders/SelectedGeometry_Anim.glsl Removes legacy Sandbox shader (deleted).
Sandbox/Resources/Shaders/Renderer2D.glsl Removes legacy Sandbox shader (deleted).
Sandbox/Resources/Shaders/Renderer2D_Text.glsl Removes legacy Sandbox shader (deleted).
Sandbox/Resources/Shaders/Renderer2D_Line.glsl Removes legacy Sandbox shader (deleted).

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

Comment on lines +112 to +115
project->m_ProjectFilePath = path.lexically_normal();
project->m_ProjectDirectory = path.parent_path();
project->m_Config.ProjectDirectory = project->m_ProjectDirectory;
project->m_Config.ProjectFileName = project->m_ProjectFilePath.filename().string();
Comment on lines +1935 to +1937
const std::filesystem::path scriptModule = Project::GetActiveScriptModuleFilePath();
if (std::filesystem::exists(scriptModule, ec))
CopyFileIfExists(scriptModule, exportAssets / project->GetConfig().ScriptModulePath);
return;
}

CopyFileIfExists(Project::GetActiveAssetDirectory() / s_RuntimeAssetPackFile, exportAssets / s_RuntimeAssetPackFile, true);
Comment on lines +1867 to +1869
const std::string buildName = SanitizeBuildName(project->GetConfig().Name);
const std::filesystem::path exportRoot = selectedFolder / (buildName + "-Windows-x86_64");
const std::filesystem::path exportAssets = exportRoot / "Assets";
Comment on lines +182 to +186
for (const auto& entry : std::filesystem::recursive_directory_iterator(source, ec))
{
if (ec)
break;

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Core/Source/Lux/Project/Project.cpp`:
- Around line 69-70: The early return when s_ActiveProject is null in
Project::SetActiveRuntime skips the cleanup that should uninitialize the audio
engine; remove the early return (or move the cleanup block above it) so the
audio shutdown logic always runs when SetActiveRuntime(nullptr, nullptr) is
called, and explicitly invoke the audio cleanup/uninitialize routine used by the
project (the audio shutdown function your project normally calls during project
teardown) as part of the same cleanup sequence to ensure the audio engine is
always shut down even if s_ActiveProject is nullptr.

In `@Core/Source/Lux/Renderer/Framebuffer.cpp`:
- Around line 64-68: Add a guard when handling m_Specification.SwapChainTarget
in the Framebuffer constructor so we don't early-return with zero attachments:
before the "if (m_Specification.SwapChainTarget) { PopulateClearValues(...);
return; }" check, validate that m_Specification.Attachments is not empty (or
assert/log+return) and fail-fast if it is, ensuring PopulateClearValues is only
called when there are attachments and preventing m_ClearValues from remaining
empty; reference m_Specification.SwapChainTarget, m_Specification.Attachments,
PopulateClearValues, and m_ClearValues.

In `@Core/Source/Lux/Scripting/ScriptEngine.cpp`:
- Around line 239-248: The shutdown sequence must stop and reset the
AppAssemblyFileWatcher before tearing down s_Data/AppDomain to avoid races;
update the code in ScriptEngine (around mono_domain_unload and s_Data handling)
to stop/unregister the AppAssemblyFileWatcher and set it to nullptr before
calling mono_domain_unload and clearing s_Data, and also update the
OnAppAssemblyFileSystemEvent callback/lambdas to defensively check s_Data and
s_Data->RootDomain (or capture weak state) before dereferencing; ensure
AppAssemblyFileWatcher::Stop/Unregister is invoked prior to mono_domain_unload
and that any remaining callbacks bail out if s_Data is null.

In `@Lux-Runtime/premake5.lua`:
- Around line 47-48: The call to os.outputof("pkg-config --libs gtk+-3.0") is
executed unconditionally during script load; wrap that call in a host check so
it only runs on Linux: use a local variable (e.g. local result, err) and call
os.outputof only when os.host() == "linux", then validate result and error out
or raise a clear message if the output is empty/invalid; remove the redundant
inner filter "system:linux" around the exec and keep the Premake filter
"system:linux" only for applying linkoptions { result } so linkoptions is set
only on Linux when result is present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 71882a7f-1c2c-45bf-b259-1b7db5f7c0b2

📥 Commits

Reviewing files that changed from the base of the PR and between d6efc93 and ba39683.

⛔ Files ignored due to path filters (107)
  • Lux-Runtime/Lux-Runtime.ico is excluded by !**/*.ico
  • Sandbox/Resources/Fonts/FontAwesome/fontawesome-webfont.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/Roboto/Roboto-Black.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/Roboto/Roboto-BlackItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/Roboto/Roboto-Bold.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/Roboto/Roboto-BoldItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/Roboto/Roboto-Italic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/Roboto/Roboto-Light.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/Roboto/Roboto-LightItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/Roboto/Roboto-Medium.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/Roboto/Roboto-MediumItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/Roboto/Roboto-Regular.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/Roboto/Roboto-SemiMedium.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/Roboto/Roboto-Thin.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/Roboto/Roboto-ThinItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/SourceCodePro-Italic-VariableFont_wght.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/SourceCodePro-VariableFont_wght.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-Black.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-BlackItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-Bold.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-BoldItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-ExtraBold.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-ExtraBoldItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-ExtraLight.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-ExtraLightItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-Italic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-Light.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-LightItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-Medium.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-MediumItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-Regular.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-SemiBold.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/SourceCodePro/static/SourceCodePro-SemiBoldItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/opensans/OpenSans-Bold.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/opensans/OpenSans-BoldItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/opensans/OpenSans-ExtraBold.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/opensans/OpenSans-ExtraBoldItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/opensans/OpenSans-Italic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/opensans/OpenSans-Light.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/opensans/OpenSans-LightItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/opensans/OpenSans-Regular.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/opensans/OpenSans-SemiBold.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Fonts/opensans/OpenSans-SemiBoldItalic.ttf is excluded by !**/*.ttf
  • Sandbox/Resources/Renderer/BRDF_LUT.png is excluded by !**/*.png
  • Sandbox/Resources/Shaders/DirShadowMap.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/DirShadowMap_Anim.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/EnvironmentIrradiance.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/EnvironmentMipFilter.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/EquirectangularToCubeMap.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/Grid.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/HZB.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/HazelPBR_Anim.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/HazelPBR_Static.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/HazelPBR_Transparent.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/ImGui.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/ImGui.hlsl is excluded by !**/*.hlsl
  • Sandbox/Resources/Shaders/JumpFlood_Composite.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/JumpFlood_Init.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/JumpFlood_Pass.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/LightCulling.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/LinearSample.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/LinearSampleUInt.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/PostProcessing/AO-Composite.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/PostProcessing/Bloom.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/PostProcessing/DOF.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/PostProcessing/EdgeDetection.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/PostProcessing/GTAO-Denoise.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/PostProcessing/GTAO.hlsl is excluded by !**/*.hlsl
  • Sandbox/Resources/Shaders/PostProcessing/Pre-Convolution.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/PostProcessing/SSR-Composite.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/PostProcessing/SSR.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/PostProcessing/SceneComposite.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/Pre-Integration.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/PreDepth.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/PreDepth_Anim.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/PreethamSky.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/Renderer2D.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/Renderer2D_Circle.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/Renderer2D_Line.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/Renderer2D_Text.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/SelectedGeometry.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/SelectedGeometry_Anim.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/Skybox.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/SpotShadowMap.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/SpotShadowMap_Anim.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/TexturePass.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/Wireframe.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/Wireframe_Anim.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Shaders/shader.glsl is excluded by !**/*.glsl
  • Sandbox/Resources/Textures/ErrorTexture.png is excluded by !**/*.png
  • Sandbox/assets/fonts/opensans/OpenSans-Bold.ttf is excluded by !**/*.ttf
  • Sandbox/assets/fonts/opensans/OpenSans-BoldItalic.ttf is excluded by !**/*.ttf
  • Sandbox/assets/fonts/opensans/OpenSans-ExtraBold.ttf is excluded by !**/*.ttf
  • Sandbox/assets/fonts/opensans/OpenSans-ExtraBoldItalic.ttf is excluded by !**/*.ttf
  • Sandbox/assets/fonts/opensans/OpenSans-Italic.ttf is excluded by !**/*.ttf
  • Sandbox/assets/fonts/opensans/OpenSans-Light.ttf is excluded by !**/*.ttf
  • Sandbox/assets/fonts/opensans/OpenSans-LightItalic.ttf is excluded by !**/*.ttf
  • Sandbox/assets/fonts/opensans/OpenSans-Medium.ttf is excluded by !**/*.ttf
  • Sandbox/assets/fonts/opensans/OpenSans-MediumItalic.ttf is excluded by !**/*.ttf
  • Sandbox/assets/fonts/opensans/OpenSans-Regular.ttf is excluded by !**/*.ttf
  • Sandbox/assets/fonts/opensans/OpenSans-SemiBold.ttf is excluded by !**/*.ttf
  • Sandbox/assets/fonts/opensans/OpenSans-SemiBoldItalic.ttf is excluded by !**/*.ttf
  • Sandbox/assets/game/textures/RPGpack_sheet_2X.png is excluded by !**/*.png
  • Sandbox/assets/shaders/FlatColor.glsl is excluded by !**/*.glsl
  • Sandbox/assets/shaders/Texture.glsl is excluded by !**/*.glsl
  • Sandbox/assets/textures/Checkerboard.png is excluded by !**/*.png
  • Sandbox/assets/textures/luxLogo.png is excluded by !**/*.png
📒 Files selected for processing (44)
  • .gitignore
  • Core/Source/Lux/Project/Project.cpp
  • Core/Source/Lux/Project/Project.h
  • Core/Source/Lux/Renderer/Framebuffer.cpp
  • Core/Source/Lux/Renderer/Framebuffer.h
  • Core/Source/Lux/Scripting/ScriptEngine.cpp
  • Editor/SandboxProject/Assets/Scenes/NewSceneSystem.luxscene
  • Editor/SandboxProject/Sandbox.luxproj
  • Editor/Source/EditorLayer.cpp
  • Editor/Source/EditorLayer.h
  • Editor/Source/LuxEditorApp.cpp
  • Editor/Source/Panels/ProjectSettingsWindow.cpp
  • Lux-Runtime/Lux-Runtime.rc
  • Lux-Runtime/premake5.lua
  • Lux-Runtime/resource.h
  • Lux-Runtime/src/RuntimeApplication.cpp
  • Lux-Runtime/src/RuntimeLayer.cpp
  • Lux-Runtime/src/RuntimeLayer.h
  • README.md
  • Sandbox/Resources/Fonts/FontAwesome/LICENSE.txt
  • Sandbox/Resources/Fonts/Roboto/LICENSE.txt
  • Sandbox/Resources/Fonts/SourceCodePro/OFL.txt
  • Sandbox/Resources/Fonts/SourceCodePro/README.txt
  • Sandbox/Resources/Fonts/msgothic.ttc
  • Sandbox/Resources/Fonts/opensans/LICENSE.txt
  • Sandbox/Resources/Shaders/Include/Common/Common.slh
  • Sandbox/Resources/Shaders/Include/Common/GTAO.slh
  • Sandbox/Resources/Shaders/Include/GLSL/Buffers.glslh
  • Sandbox/Resources/Shaders/Include/GLSL/Common.glslh
  • Sandbox/Resources/Shaders/Include/GLSL/EnvironmentMapping.glslh
  • Sandbox/Resources/Shaders/Include/GLSL/Lighting.glslh
  • Sandbox/Resources/Shaders/Include/GLSL/PBR.glslh
  • Sandbox/Resources/Shaders/Include/GLSL/PBR_Resources.glslh
  • Sandbox/Resources/Shaders/Include/GLSL/Samplers.glslh
  • Sandbox/Resources/Shaders/Include/GLSL/ShadowMapping.glslh
  • Sandbox/Resources/Shaders/Include/HLSL/Buffers.hlslh
  • Sandbox/Resources/Shaders/Include/HLSL/Types.hlslh
  • Sandbox/Source/Sandbox2D.cpp
  • Sandbox/Source/Sandbox2D.h
  • Sandbox/Source/SandboxApp.cpp
  • Sandbox/assets/fonts/opensans/LICENSE.txt
  • Sandbox/premake5.lua
  • premake5.lua
  • scripts/Linux-Build.sh
💤 Files with no reviewable changes (23)
  • Sandbox/Resources/Fonts/opensans/LICENSE.txt
  • Sandbox/Resources/Fonts/SourceCodePro/README.txt
  • Sandbox/Resources/Shaders/Include/Common/Common.slh
  • Sandbox/Resources/Fonts/SourceCodePro/OFL.txt
  • Sandbox/Source/Sandbox2D.h
  • scripts/Linux-Build.sh
  • Sandbox/Resources/Shaders/Include/GLSL/Common.glslh
  • Sandbox/Resources/Shaders/Include/Common/GTAO.slh
  • Sandbox/Resources/Shaders/Include/GLSL/PBR_Resources.glslh
  • Sandbox/Resources/Shaders/Include/HLSL/Buffers.hlslh
  • Sandbox/Resources/Shaders/Include/GLSL/Lighting.glslh
  • Sandbox/Resources/Fonts/FontAwesome/LICENSE.txt
  • Sandbox/Resources/Shaders/Include/GLSL/EnvironmentMapping.glslh
  • Sandbox/Resources/Shaders/Include/GLSL/PBR.glslh
  • Sandbox/Source/SandboxApp.cpp
  • Sandbox/Resources/Fonts/Roboto/LICENSE.txt
  • Sandbox/Source/Sandbox2D.cpp
  • Sandbox/Resources/Shaders/Include/GLSL/Buffers.glslh
  • Sandbox/assets/fonts/opensans/LICENSE.txt
  • Sandbox/Resources/Shaders/Include/GLSL/ShadowMapping.glslh
  • Sandbox/Resources/Shaders/Include/HLSL/Types.hlslh
  • Sandbox/premake5.lua
  • Sandbox/Resources/Shaders/Include/GLSL/Samplers.glslh

Comment on lines 69 to 70
if (!s_ActiveProject)
return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not skip audio shutdown when clearing the active runtime project.

Line 70 returns on nullptr and bypasses the cleanup block at Line 80, so Project::SetActiveRuntime(nullptr, nullptr) can leave the audio engine initialized.

🛠️ Suggested fix
 		s_ActiveProject = project;
-		if (!s_ActiveProject)
-			return;
-
-		if (s_ActiveProject->m_ProjectDirectory.empty())
-			s_ActiveProject->m_ProjectDirectory = s_ActiveProject->m_Config.ProjectDirectory;
-		if (s_ActiveProject->m_ProjectFilePath.empty() && !s_ActiveProject->m_ProjectDirectory.empty())
-			s_ActiveProject->m_ProjectFilePath = s_ActiveProject->m_ProjectDirectory / s_ActiveProject->m_Config.ProjectFileName;
-
-		s_ActiveProject->m_Config.ProjectDirectory = s_ActiveProject->m_ProjectDirectory;
-		s_ActiveProject->m_Config.ProjectFileName = s_ActiveProject->m_ProjectFilePath.filename().string();
-
 		if (AudioEngine::HasInitializedEngine())
 		{
 			AudioEngine::Shutdown();
 			AudioEngine::SetInitalizedEngine(false);
 		}
+
+		if (!s_ActiveProject)
+			return;
+
+		if (s_ActiveProject->m_ProjectDirectory.empty())
+			s_ActiveProject->m_ProjectDirectory = s_ActiveProject->m_Config.ProjectDirectory;
+		if (s_ActiveProject->m_ProjectFilePath.empty() && !s_ActiveProject->m_ProjectDirectory.empty())
+			s_ActiveProject->m_ProjectFilePath = s_ActiveProject->m_ProjectDirectory / s_ActiveProject->m_Config.ProjectFileName;
+
+		s_ActiveProject->m_Config.ProjectDirectory = s_ActiveProject->m_ProjectDirectory;
+		s_ActiveProject->m_Config.ProjectFileName = s_ActiveProject->m_ProjectFilePath.filename().string();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!s_ActiveProject)
return;
s_ActiveProject = project;
if (AudioEngine::HasInitializedEngine())
{
AudioEngine::Shutdown();
AudioEngine::SetInitalizedEngine(false);
}
if (!s_ActiveProject)
return;
if (s_ActiveProject->m_ProjectDirectory.empty())
s_ActiveProject->m_ProjectDirectory = s_ActiveProject->m_Config.ProjectDirectory;
if (s_ActiveProject->m_ProjectFilePath.empty() && !s_ActiveProject->m_ProjectDirectory.empty())
s_ActiveProject->m_ProjectFilePath = s_ActiveProject->m_ProjectDirectory / s_ActiveProject->m_Config.ProjectFileName;
s_ActiveProject->m_Config.ProjectDirectory = s_ActiveProject->m_ProjectDirectory;
s_ActiveProject->m_Config.ProjectFileName = s_ActiveProject->m_ProjectFilePath.filename().string();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Core/Source/Lux/Project/Project.cpp` around lines 69 - 70, The early return
when s_ActiveProject is null in Project::SetActiveRuntime skips the cleanup that
should uninitialize the audio engine; remove the early return (or move the
cleanup block above it) so the audio shutdown logic always runs when
SetActiveRuntime(nullptr, nullptr) is called, and explicitly invoke the audio
cleanup/uninitialize routine used by the project (the audio shutdown function
your project normally calls during project teardown) as part of the same cleanup
sequence to ensure the audio engine is always shut down even if s_ActiveProject
is nullptr.

Comment on lines +64 to +68
if (m_Specification.SwapChainTarget)
{
PopulateClearValues(m_Specification, m_ClearValues);
return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a swapchain-target attachment guard before the early return.

Line 67 returns before the constructor reaches the general attachment validation, so a swapchain framebuffer with zero attachments can leave m_ClearValues empty and later break clear indexing during render-pass setup.

🛠️ Suggested fix
 		if (m_Specification.SwapChainTarget)
 		{
+			LUX_CORE_ASSERT(!m_Specification.Attachments.Attachments.empty(), "SwapChainTarget framebuffer requires at least one attachment");
 			PopulateClearValues(m_Specification, m_ClearValues);
 			return;
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Core/Source/Lux/Renderer/Framebuffer.cpp` around lines 64 - 68, Add a guard
when handling m_Specification.SwapChainTarget in the Framebuffer constructor so
we don't early-return with zero attachments: before the "if
(m_Specification.SwapChainTarget) { PopulateClearValues(...); return; }" check,
validate that m_Specification.Attachments is not empty (or assert/log+return)
and fail-fast if it is, ensuring PopulateClearValues is only called when there
are attachments and preventing m_ClearValues from remaining empty; reference
m_Specification.SwapChainTarget, m_Specification.Attachments,
PopulateClearValues, and m_ClearValues.

Comment on lines +239 to +248
if (!s_Data || !s_Data->RootDomain)
return;

mono_domain_set(mono_get_root_domain(), false);

mono_domain_unload(s_Data->AppDomain);
s_Data->AppDomain = nullptr;
if (s_Data->AppDomain)
{
mono_domain_unload(s_Data->AppDomain);
s_Data->AppDomain = nullptr;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Stop file-watch callbacks before domain teardown to avoid shutdown races.

AppAssemblyFileWatcher can still trigger OnAppAssemblyFileSystemEvent while shutdown is in progress; that path dereferences s_Data and can crash after Line 205 sets it to nullptr. Reset the watcher before unload and guard callback/lambda dereferences.

Proposed fix
diff --git a/Core/Source/Lux/Scripting/ScriptEngine.cpp b/Core/Source/Lux/Scripting/ScriptEngine.cpp
@@
 static void OnAppAssemblyFileSystemEvent(const std::string& path, const filewatch::Event change_type)
 {
+    if (!s_Data)
+        return;
+
     if (!s_Data->AssemblyReloadPending && change_type == filewatch::Event::modified)
     {
         s_Data->AssemblyReloadPending = true;
 
         Application::Get().QueueEvent([]()
             {
+                if (!s_Data)
+                    return;
                 s_Data->AppAssemblyFileWatcher.reset();
                 ScriptEngine::ReloadAssembly();
             });
     }
 }
@@
 void ScriptEngine::Shutdown()
 {
     if (!s_Data)
         return;
 
+    s_Data->AppAssemblyFileWatcher.reset();
     ShutdownMono();
     delete s_Data;
     s_Data = nullptr;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Core/Source/Lux/Scripting/ScriptEngine.cpp` around lines 239 - 248, The
shutdown sequence must stop and reset the AppAssemblyFileWatcher before tearing
down s_Data/AppDomain to avoid races; update the code in ScriptEngine (around
mono_domain_unload and s_Data handling) to stop/unregister the
AppAssemblyFileWatcher and set it to nullptr before calling mono_domain_unload
and clearing s_Data, and also update the OnAppAssemblyFileSystemEvent
callback/lambdas to defensively check s_Data and s_Data->RootDomain (or capture
weak state) before dereferencing; ensure AppAssemblyFileWatcher::Stop/Unregister
is invoked prior to mono_domain_unload and that any remaining callbacks bail out
if s_Data is null.

Comment thread Lux-Runtime/premake5.lua
Comment on lines +47 to +48
result, err = os.outputof("pkg-config --libs gtk+-3.0")
linkoptions { result }
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Premake5 behavior check: does filter "system:linux"apply only to Premake API calls (e.g.,links, defines) and not to plain Lua statements like os.outputof(...)?

💡 Result:

Yes. filter "system:linux" only affects Premake API calls that add/modify settings in Premake’s internal output model (e.g., defines, links, includedirs, etc.). It does not “guard” plain Lua statements from executing. 1) What filter actually does (Premake model scoping) Premake’s filter documentation says calling filter() makes that filter condition “active”, and “All settings which subsequently appear in the script will be filtered by this condition” until a new filter or container is activated [1]. This implies it gates Premake “settings” (i.e., the things that Premake APIs record for later generation), not arbitrary Lua code. It also states that filters are “evaluated at generation time” based on the currently generated configuration/project context [1]. That further indicates the filter isn’t a runtime Lua control-flow construct; it’s a selection mechanism for what ends up in generated project files. 2) Direct evidence: os.outputof(...) runs regardless of the active filter An issue discussion explicitly demonstrates this with os.outputof(...) inside filter "system:windows" / filter "system:linux" blocks. The author explains that “filter... is just a call to a function, that has no effect on the execution order”, and shows that what looks like conditional execution is really just sequential Lua function calls; filter “add[s] a ‘block’ to the internal premake tree” while the Lua code (including os.outputof) executes during script loading [2]. So if you write: filter "system:linux" local tmp = os.outputof("linuxcommand...") then the os.outputof(...) call still executes when Premake parses/loads the script, regardless of whether the generator is targeting Linux. The filter only determines whether any Premake settings you emit after it end up in the Linux-specific generated output [1][2]. Bottom line Use normal Lua conditionals (e.g., if os.host() == "linux" then ... end) when you need to conditionally execute Lua code at script-load time [3]. Use filter "system:linux" when you want certain Premake settings to appear only in the generated output for Linux configurations [1].

Citations:


Guard pkg-config execution with os.host(); filter "system:linux" doesn’t prevent Lua from running

filter "system:linux" only scopes Premake settings—it doesn’t guard execution of plain Lua, so os.outputof("pkg-config --libs gtk+-3.0") can still run during script load on non-Linux hosts. Keep the output in a local variable and run the os.outputof call only when os.host() == "linux", failing clearly when output is missing.

  • The proposed fix is directionally correct, but the inner filter "system:linux" in the diff is redundant.
Proposed fix
 filter "system:linux"
 		defines { "LUX_PLATFORM_LINUX", "__EMULATE_UUID", "BACKWARD_HAS_DW", "BACKWARD_HAS_LIBUNWIND" }
 		links { "dw", "dl", "unwind", "pthread" }
 
-		result, err = os.outputof("pkg-config --libs gtk+-3.0")
-		linkoptions { result }
+if os.host() == "linux" then
+		local gtk_libs = os.outputof("pkg-config --libs gtk+-3.0")
+		if not gtk_libs or gtk_libs == "" then
+				error("pkg-config --libs gtk+-3.0 failed. Install gtk+-3.0 development packages and pkg-config.")
+		end
+		filter "system:linux"
+				linkoptions { gtk_libs }
+end
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Lux-Runtime/premake5.lua` around lines 47 - 48, The call to
os.outputof("pkg-config --libs gtk+-3.0") is executed unconditionally during
script load; wrap that call in a host check so it only runs on Linux: use a
local variable (e.g. local result, err) and call os.outputof only when os.host()
== "linux", then validate result and error out or raise a clear message if the
output is empty/invalid; remove the redundant inner filter "system:linux" around
the exec and keep the Premake filter "system:linux" only for applying
linkoptions { result } so linkoptions is set only on Linux when result is
present.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants