diff --git a/Source/Editor/Cooker/CookingData.h b/Source/Editor/Cooker/CookingData.h
index 5f91638ad..1f62a7738 100644
--- a/Source/Editor/Cooker/CookingData.h
+++ b/Source/Editor/Cooker/CookingData.h
@@ -26,6 +26,16 @@ API_ENUM(Attributes="Flags") enum class BuildOptions
/// Shows the output directory folder on building end.
///
ShowOutput = 1 << 0,
+
+ ///
+ /// Starts the cooked game build on building end.
+ ///
+ AutoRun = 1 << 1,
+
+ ///
+ /// Skips cooking logic and uses already cooked data (eg. to only use AutoRun or ShowOutput feature).
+ ///
+ NoCook = 1 << 2,
};
DECLARE_ENUM_OPERATORS(BuildOptions);
diff --git a/Source/Editor/Cooker/GameCooker.cpp b/Source/Editor/Cooker/GameCooker.cpp
index 01d09bfbf..cdd51ed55 100644
--- a/Source/Editor/Cooker/GameCooker.cpp
+++ b/Source/Editor/Cooker/GameCooker.cpp
@@ -430,6 +430,52 @@ void GameCooker::Cancel(bool waitForEnd)
}
}
+void GameCooker::GetCurrentPlatform(PlatformType& platform, BuildPlatform& buildPlatform, BuildConfiguration& buildConfiguration)
+{
+ platform = PLATFORM_TYPE;
+#if BUILD_DEBUG
+ buildConfiguration = BuildConfiguration::Debug;
+#elif BUILD_DEVELOPMENT
+ buildConfiguration = BuildConfiguration::Development;
+#elif BUILD_RELEASE
+ buildConfiguration = BuildConfiguration::Release;
+#endif
+ switch (PLATFORM_TYPE)
+ {
+ case PlatformType::Windows:
+ buildPlatform = PLATFORM_64BITS ? BuildPlatform::Windows64 : BuildPlatform::Windows32;
+ break;
+ case PlatformType::XboxOne:
+ buildPlatform = BuildPlatform::XboxOne;
+ break;
+ case PlatformType::UWP:
+ buildPlatform = BuildPlatform::UWPx64;
+ break;
+ case PlatformType::Linux:
+ buildPlatform = BuildPlatform::LinuxX64;
+ break;
+ case PlatformType::PS4:
+ buildPlatform = BuildPlatform::PS4;
+ break;
+ case PlatformType::XboxScarlett:
+ buildPlatform = BuildPlatform::XboxScarlett;
+ break;
+ case PlatformType::Android:
+ buildPlatform = BuildPlatform::AndroidARM64;
+ break;
+ case PlatformType::Switch:
+ buildPlatform = BuildPlatform::Switch;
+ break;
+ case PlatformType::PS5:
+ buildPlatform = BuildPlatform::PS5;
+ break;
+ case PlatformType::Mac:
+ buildPlatform = BuildPlatform::MacOSx64;
+ break;
+ default: ;
+ }
+}
+
void GameCookerImpl::CallEvent(GameCooker::EventType type)
{
if (Internal_OnEvent == nullptr)
@@ -492,7 +538,6 @@ bool GameCookerImpl::Build()
// Late init feature
if (Steps.IsEmpty())
{
- // Create steps
Steps.Add(New());
Steps.Add(New());
Steps.Add(New());
@@ -517,6 +562,8 @@ bool GameCookerImpl::Build()
{
if (GameCooker::IsCancelRequested())
break;
+ if (data.Options & BuildOptions::NoCook)
+ continue;
auto step = Steps[stepIndex];
data.NextStep();
@@ -544,6 +591,24 @@ bool GameCookerImpl::Build()
{
FileSystem::ShowFileExplorer(data.OriginalOutputPath);
}
+
+ if (data.Options & BuildOptions::AutoRun)
+ {
+ String executableFile, commandLineFormat, workingDir;
+ data.Tools->OnRun(data, executableFile, commandLineFormat, workingDir);
+ if (executableFile.HasChars())
+ {
+ const String gameArgs; // TODO: pass custom game run args from Editor? eg. starting map? or client info?
+ const String commandLine = commandLineFormat.HasChars() ? String::Format(*commandLineFormat, gameArgs) : gameArgs;
+ if (workingDir.IsEmpty())
+ workingDir = data.NativeCodeOutputPath;
+ Platform::StartProcess(executableFile, commandLine, workingDir);
+ }
+ else
+ {
+ LOG(Warning, "Missing executable to run or platform doesn't support build&run.");
+ }
+ }
}
IsRunning = false;
CancelFlag = 0;
diff --git a/Source/Editor/Cooker/GameCooker.h b/Source/Editor/Cooker/GameCooker.h
index 981151c63..6ff563e26 100644
--- a/Source/Editor/Cooker/GameCooker.h
+++ b/Source/Editor/Cooker/GameCooker.h
@@ -90,6 +90,11 @@ public:
/// If set to true wait for the stopped building end.
API_FUNCTION() static void Cancel(bool waitForEnd = false);
+ ///
+ /// Gets the current Editor build info (platform, configuration, etc).
+ ///
+ API_FUNCTION() static void GetCurrentPlatform(API_PARAM(Out) PlatformType& platform, API_PARAM(Out) BuildPlatform& buildPlatform, API_PARAM(Out) BuildConfiguration& buildConfiguration);
+
///
/// Building event type.
///
diff --git a/Source/Editor/Cooker/Platform/Windows/WindowsPlatformTools.cpp b/Source/Editor/Cooker/Platform/Windows/WindowsPlatformTools.cpp
index 57183df5b..457c068c9 100644
--- a/Source/Editor/Cooker/Platform/Windows/WindowsPlatformTools.cpp
+++ b/Source/Editor/Cooker/Platform/Windows/WindowsPlatformTools.cpp
@@ -36,11 +36,10 @@ ArchitectureType WindowsPlatformTools::GetArchitecture() const
bool WindowsPlatformTools::OnDeployBinaries(CookingData& data)
{
const auto platformSettings = WindowsPlatformSettings::Get();
- const auto& outputPath = data.NativeCodeOutputPath;
// Apply executable icon
Array files;
- FileSystem::DirectoryGetFiles(files, outputPath, TEXT("*.exe"), DirectorySearchOption::TopDirectoryOnly);
+ FileSystem::DirectoryGetFiles(files, data.NativeCodeOutputPath, TEXT("*.exe"), DirectorySearchOption::TopDirectoryOnly);
if (files.HasItems())
{
TextureData iconData;
@@ -57,4 +56,15 @@ bool WindowsPlatformTools::OnDeployBinaries(CookingData& data)
return false;
}
+void WindowsPlatformTools::OnRun(CookingData& data, String& executableFile, String& commandLineFormat, String& workingDir)
+{
+ // Pick the first executable file
+ Array files;
+ FileSystem::DirectoryGetFiles(files, data.NativeCodeOutputPath, TEXT("*.exe"), DirectorySearchOption::TopDirectoryOnly);
+ if (files.HasItems())
+ {
+ executableFile = files[0];
+ }
+}
+
#endif
diff --git a/Source/Editor/Cooker/Platform/Windows/WindowsPlatformTools.h b/Source/Editor/Cooker/Platform/Windows/WindowsPlatformTools.h
index a6ae40fd4..404a9f9d6 100644
--- a/Source/Editor/Cooker/Platform/Windows/WindowsPlatformTools.h
+++ b/Source/Editor/Cooker/Platform/Windows/WindowsPlatformTools.h
@@ -30,6 +30,7 @@ public:
PlatformType GetPlatform() const override;
ArchitectureType GetArchitecture() const override;
bool OnDeployBinaries(CookingData& data) override;
+ void OnRun(CookingData& data, String& executableFile, String& commandLineFormat, String& workingDir) override;
};
#endif
diff --git a/Source/Editor/Cooker/PlatformTools.h b/Source/Editor/Cooker/PlatformTools.h
index ac07c88af..58888964f 100644
--- a/Source/Editor/Cooker/PlatformTools.h
+++ b/Source/Editor/Cooker/PlatformTools.h
@@ -203,4 +203,15 @@ public:
{
return false;
}
+
+ ///
+ /// Called to run the cooked game build on device.
+ ///
+ /// The cooking data.
+ /// The game executable file path to run (or tool path to run if build should run on remote device). Empty if not supported.
+ /// The command line for executable file. Use `{0}` to insert custom command line for passing to the cooked game.
+ /// Overriden custom working directory to use. Leave empty if use cooked data output folder.
+ virtual void OnRun(CookingData& data, String& executableFile, String& commandLineFormat, String& workingDir)
+ {
+ }
};
diff --git a/Source/Editor/Modules/UIModule.cs b/Source/Editor/Modules/UIModule.cs
index 7c71c5628..829ad5e00 100644
--- a/Source/Editor/Modules/UIModule.cs
+++ b/Source/Editor/Modules/UIModule.cs
@@ -485,6 +485,9 @@ namespace FlaxEditor.Modules
cm.VisibleChanged += OnMenuGameShowHide;
_menuGamePlay = cm.AddButton("Play", "F5", Editor.Simulation.RequestStartPlay);
_menuGamePause = cm.AddButton("Pause", "F6", Editor.Simulation.RequestPausePlay);
+ cm.AddSeparator();
+ cm.AddButton("Cook&Run", Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip("Runs Game Cooker to build the game for this platform and runs the game after.");
+ cm.AddButton("Run cooked game", Editor.Windows.GameCookerWin.RunCooked).LinkTooltip("Runs the game build from the last cooking output. Use Cook&Play or Game Cooker first.");
// Tools
MenuTools = MainMenu.AddButton("Tools");
diff --git a/Source/Editor/Windows/GameCookerWindow.cs b/Source/Editor/Windows/GameCookerWindow.cs
index 58b7ac5cc..e2fb99464 100644
--- a/Source/Editor/Windows/GameCookerWindow.cs
+++ b/Source/Editor/Windows/GameCookerWindow.cs
@@ -35,7 +35,7 @@ namespace FlaxEditor.Windows
public readonly GameCookerWindow GameCookerWin;
public readonly PlatformSelector Selector;
- private readonly Dictionary PerPlatformOptions = new Dictionary
+ internal readonly Dictionary PerPlatformOptions = new Dictionary
{
{ PlatformType.Windows, new Windows() },
{ PlatformType.XboxOne, new XboxOne() },
@@ -67,7 +67,7 @@ namespace FlaxEditor.Windows
}
[HideInEditor]
- abstract class Platform
+ internal abstract class Platform
{
[HideInEditor]
public bool IsSupported;
@@ -490,10 +490,12 @@ namespace FlaxEditor.Windows
{
public string PresetName;
public BuildTarget Target;
+ public BuildOptions Options;
}
private PresetsColumn _presets;
private TargetsColumn _targets;
+ private BuildTabProxy _buildTabProxy;
private int _selectedPresetIndex = -1;
private int _selectedTargetIndex = -1;
private CustomEditorPresenter _targetSettings;
@@ -617,6 +619,44 @@ namespace FlaxEditor.Windows
});
}
+ ///
+ /// Builds the target for this platform and runs it on this device.
+ ///
+ public void BuildAndRun()
+ {
+ Editor.Log("Building and running");
+ GameCooker.GetCurrentPlatform(out var platform, out var buildPlatform, out var buildConfiguration);
+ _buildingQueue.Enqueue(new QueueItem
+ {
+ Target = new BuildTarget
+ {
+ Output = _buildTabProxy.PerPlatformOptions[platform].Output,
+ Platform = buildPlatform,
+ Mode = buildConfiguration,
+ },
+ Options = BuildOptions.AutoRun,
+ });
+ }
+
+ ///
+ /// Runs the cooked game for this platform on this device.
+ ///
+ public void RunCooked()
+ {
+ Editor.Log("Running cooked build");
+ GameCooker.GetCurrentPlatform(out var platform, out var buildPlatform, out var buildConfiguration);
+ _buildingQueue.Enqueue(new QueueItem
+ {
+ Target = new BuildTarget
+ {
+ Output = _buildTabProxy.PerPlatformOptions[platform].Output,
+ Platform = buildPlatform,
+ Mode = buildConfiguration,
+ },
+ Options = BuildOptions.AutoRun | BuildOptions.NoCook,
+ });
+ }
+
private void BuildTarget()
{
if (_data == null || _data.Length <= _selectedPresetIndex || _selectedPresetIndex == -1)
@@ -829,7 +869,8 @@ namespace FlaxEditor.Windows
var settings = new CustomEditorPresenter(null);
settings.Panel.Parent = panel;
- settings.Select(new BuildTabProxy(this, platformSelector));
+ _buildTabProxy = new BuildTabProxy(this, platformSelector);
+ settings.Select(_buildTabProxy);
}
private void OnPlatformSelectorSizeChanged(Control platformSelector)
@@ -894,7 +935,7 @@ namespace FlaxEditor.Windows
_preBuildAction = target.PreBuildAction;
_postBuildAction = target.PostBuildAction;
- GameCooker.Build(target.Platform, target.Mode, target.Output, BuildOptions.None, target.CustomDefines, item.PresetName, target.Name);
+ GameCooker.Build(target.Platform, target.Mode, target.Output, item.Options, target.CustomDefines, item.PresetName, target.Name);
}
else if (_exitOnBuildEnd)
{
@@ -908,6 +949,7 @@ namespace FlaxEditor.Windows
public override void OnDestroy()
{
GameCooker.Event -= OnGameCookerEvent;
+ _buildTabProxy = null;
base.OnDestroy();
}