Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ let package = Package(
// Use a branch during active development:
// .package(url: "https://github.com/untoldengine/UntoldEngine.git", branch: "develop"),
// Or pin to a release:
.package(url: "https://github.com/untoldengine/UntoldEngine.git", exact: "0.6.2"),
.package(url: "https://github.com/untoldengine/UntoldEngine.git", exact: "0.7.0"),
],
targets: [
.executableTarget(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// BuildSettingsView.swift
// CreateProjectView.swift
// UntoldEditor
//
// Copyright (C) Untold Engine Studios
Expand All @@ -10,7 +10,7 @@
import SwiftUI
import UntoldEngine

struct BuildSettingsView: View {
struct CreateProjectView: View {
@State private var projectName: String = "MyGame"
@State private var bundleIdentifier: String = "com.yourcompany.mygame"
@State private var selectedTarget: Int = 0
Expand All @@ -25,19 +25,19 @@ struct BuildSettingsView: View {
@State private var showBuildResult: Bool = false
@State private var buildResultMessage: String = ""
@State private var buildSucceeded: Bool = false
@State private var showBasePathAlert: Bool = false
@State private var resultProjectPath: URL?

@Environment(\.dismiss) private var dismiss

private let targets = ["macOS", "iOS", "visionOS"]
private let targets = ["macOS", "iOS", "iOS AR", "visionOS"]
private let macOSVersions = ["13.0", "14.0", "15.0"]
private let optimizationLevels = ["None", "Speed", "Size"]

var body: some View {
VStack(spacing: 0) {
// Header
HStack {
Text("Build Settings")
Text("Create New Project")
.font(.title2)
.fontWeight(.semibold)
Spacer()
Expand Down Expand Up @@ -119,11 +119,10 @@ struct BuildSettingsView: View {
.background(Color(NSColor.controlBackgroundColor))
}

// Build Button
// Create Button
HStack {
Spacer()
Button("Build") {
guard ensureAssetBasePath() else { return }
Button("Create") {
startBuild()
}
.buttonStyle(.borderedProminent)
Expand All @@ -133,26 +132,27 @@ struct BuildSettingsView: View {
.background(Color(NSColor.controlBackgroundColor))
}
.frame(width: 600, height: 550)
.alert("Build Complete", isPresented: $showBuildResult) {
.alert("Project Created", isPresented: $showBuildResult) {
if buildSucceeded {
Button("Open in Finder") {
openBuildOutput()
dismiss()
}
Button("Open in Xcode") {
openInXcode()
dismiss()
}
Button("OK", role: .cancel) {
dismiss()
}
Button("OK", role: .cancel) {}
} else {
Button("OK", role: .cancel) {}
Button("OK", role: .cancel) {
dismiss()
}
}
} message: {
Text(buildResultMessage)
}
.alert("Set Asset Folder First", isPresented: $showBasePathAlert) {
Button("OK", role: .cancel) {}
} message: {
Text("Please set the Asset Folder in the Asset Browser before building.")
}
.onAppear {
loadDefaultSettings()
}
Expand All @@ -171,7 +171,7 @@ struct BuildSettingsView: View {
panel.canChooseDirectories = true
panel.canCreateDirectories = true
panel.allowsMultipleSelection = false
panel.message = "Choose build output directory"
panel.message = "Choose project output directory"

if panel.runModal() == .OK {
outputPath = panel.url?.path ?? outputPath
Expand All @@ -180,7 +180,7 @@ struct BuildSettingsView: View {

private func startBuild() {
isBuilding = true
buildProgress = "Preparing build..."
buildProgress = "Creating project..."

Task {
do {
Expand All @@ -195,20 +195,33 @@ struct BuildSettingsView: View {
await MainActor.run {
isBuilding = false
buildSucceeded = true
resultProjectPath = result.xcodeProjectPath.deletingLastPathComponent()
buildResultMessage = """
Build completed successfully in \(String(format: "%.2f", result.buildTime))s
Project created successfully in \(String(format: "%.2f", result.buildTime))s

Project: \(result.xcodeProjectPath.path)
Location: \(result.xcodeProjectPath.path)
Assets: \(result.bundledAssets.count) files
"""
showBuildResult = true

// Set assetBasePath to the newly created GameData folder
// This allows the editor to immediately save scenes to the correct location
let projectDir = result.xcodeProjectPath.deletingLastPathComponent()
let gameDataPath = projectDir
.appendingPathComponent("Sources")
.appendingPathComponent(settings.projectName)
.appendingPathComponent("GameData")

assetBasePath = gameDataPath
EditorAssetBasePath.shared.basePath = gameDataPath
Logger.log(message: "📁 Asset base path set to: \(gameDataPath.path)")
}

} catch {
await MainActor.run {
isBuilding = false
buildSucceeded = false
buildResultMessage = "Build failed: \(error.localizedDescription)"
buildResultMessage = "Project creation failed: \(error.localizedDescription)"
showBuildResult = true
}
}
Expand All @@ -217,6 +230,8 @@ struct BuildSettingsView: View {

private func createBuildSettings() -> BuildSettings {
let target: BuildTarget
let isIOSAR = (selectedTarget == 2) // iOS AR

switch selectedTarget {
case 0: // macOS
let version: MacOSVersion
Expand All @@ -229,8 +244,10 @@ struct BuildSettingsView: View {
target = .macOS(deployment: version)
case 1: // iOS
target = .iOS(deployment: .v17)
case 2: // visionOS
target = .visionOS(deployment: .v1)
case 2: // iOS AR
target = .iOS(deployment: .v17)
case 3: // visionOS
target = .visionOS(deployment: .v26)
default:
target = .macOS(deployment: .v15)
}
Expand All @@ -251,13 +268,18 @@ struct BuildSettingsView: View {
scenes: [], // Will be populated by BuildSystem
includeDebugInfo: includeDebugInfo,
optimizationLevel: optimization,
teamID: teamID.isEmpty ? nil : teamID
teamID: teamID.isEmpty ? nil : teamID,
isIOSAR: isIOSAR
)
}

private func openBuildOutput() {
let buildPath = URL(fileURLWithPath: outputPath).appendingPathComponent(projectName)
NSWorkspace.shared.selectFile(nil, inFileViewerRootedAtPath: buildPath.path)
if let projectPath = resultProjectPath {
NSWorkspace.shared.selectFile(nil, inFileViewerRootedAtPath: projectPath.path)
} else {
let buildPath = URL(fileURLWithPath: outputPath).appendingPathComponent(projectName)
NSWorkspace.shared.selectFile(nil, inFileViewerRootedAtPath: buildPath.path)
}
}

private func openInXcode() {
Expand All @@ -267,16 +289,8 @@ struct BuildSettingsView: View {

NSWorkspace.shared.open(xcodeProjectPath)
}

private func ensureAssetBasePath() -> Bool {
guard EditorAssetBasePath.shared.basePath != nil else {
showBasePathAlert = true
return false
}
return true
}
}

#Preview {
BuildSettingsView()
CreateProjectView()
}
36 changes: 36 additions & 0 deletions Sources/UntoldEditor/Config/EditorFeatureFlags.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// EditorFeatureFlags.swift
// UntoldEditor
//
// Copyright (C) Untold Engine Studios
// Licensed under the GNU LGPL v3.0 or later.
// See the LICENSE file or <https://www.gnu.org/licenses/> for details.
//

import Foundation

/// Feature flags for controlling experimental or deprecated features in the editor
enum EditorFeatureFlags {
// MARK: - Build System Features

/// Enable the Build button in the toolbar
/// When disabled, users should use the `untoldengine-create` CLI tool instead
static let enableBuildButton: Bool = true

// MARK: - Script Management Features

/// Enable script creation and management buttons in the toolbar
/// When disabled, users manage Swift code directly in their game project
static let enableScriptButtons: Bool = true

/// Enable the Script Component in the Inspector
/// When disabled, users write game logic in Swift within their game project
static let enableScriptComponent: Bool = true

// MARK: - Future Use Cases

// When these might be re-enabled:
// - Build button: If we add specialized build configurations not available via CLI
// - Script buttons: If we implement visual scripting / Blueprint-like system
// - Script component: If we add hot-reloading or modding support via USC scripts
}
Loading
Loading