diff --git a/Source/Editor/Editor.cpp b/Source/Editor/Editor.cpp index 2284478dd..1b18034c4 100644 --- a/Source/Editor/Editor.cpp +++ b/Source/Editor/Editor.cpp @@ -518,7 +518,7 @@ bool Editor::Init() exit(failed ? 1 : 0); return true; } - + // If during last lightmaps baking engine crashed we could try to restore the progress ShadowsOfMordor::Builder::Instance()->CheckIfRestoreState(); @@ -534,6 +534,12 @@ bool Editor::Init() // Initialize managed editor Managed->Init(); + // Start play if requested by cmd line + if (CommandLine::Options.Play.HasValue()) + { + Managed->RequestStartPlayOnEditMode(); + } + return false; } diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index adf4d566b..e7b33852b 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -46,6 +46,7 @@ namespace FlaxEditor private bool _isAfterInit, _areModulesInited, _areModulesAfterInitEnd, _isHeadlessMode; private string _projectToOpen; private float _lastAutoSaveTimer; + private Guid _startupSceneCmdLine; private const string ProjectDataLastScene = "LastScene"; private const string ProjectDataLastSceneSpawn = "LastSceneSpawn"; @@ -271,10 +272,11 @@ namespace FlaxEditor module.OnEndInit(); } - internal void Init(bool isHeadless, bool skipCompile) + internal void Init(bool isHeadless, bool skipCompile, Guid startupScene) { EnsureState(); _isHeadlessMode = isHeadless; + _startupSceneCmdLine = startupScene; Log("Editor init"); if (isHeadless) Log("Running in headless mode"); @@ -332,6 +334,17 @@ namespace FlaxEditor } // Load scene + + // scene cmd line argument + var scene = ContentDatabase.Find(_startupSceneCmdLine); + if (scene is SceneItem) + { + Editor.Log("Loading scene specified in command line"); + Scene.OpenScene(_startupSceneCmdLine); + return; + } + + // if no scene cmd line argument is provided var startupSceneMode = Options.Options.General.StartupSceneMode; if (startupSceneMode == GeneralOptions.StartupSceneModes.LastOpened && !ProjectCache.HasCustomData(ProjectDataLastScene)) { @@ -1309,6 +1322,19 @@ namespace FlaxEditor AnimGraphDebugFlow?.Invoke(debugFlow); } + private static void RequestStartPlayOnEditMode() + { + if (Instance.StateMachine.IsEditMode) + Instance.Simulation.RequestStartPlay(); + if (Instance.StateMachine.IsPlayMode) + Instance.StateMachine.StateChanged -= RequestStartPlayOnEditMode; + } + + internal static void Internal_RequestStartPlayOnEditMode() + { + Instance.StateMachine.StateChanged += RequestStartPlayOnEditMode; + } + [MethodImpl(MethodImplOptions.InternalCall)] internal static extern int Internal_ReadOutputLogs(string[] outMessages, byte[] outLogTypes, long[] outLogTimes); diff --git a/Source/Editor/Managed/ManagedEditor.cpp b/Source/Editor/Managed/ManagedEditor.cpp index 35219a906..18a905d4b 100644 --- a/Source/Editor/Managed/ManagedEditor.cpp +++ b/Source/Editor/Managed/ManagedEditor.cpp @@ -35,6 +35,7 @@ MMethod* Internal_GetGameWindowSize = nullptr; MMethod* Internal_OnAppExit = nullptr; MMethod* Internal_OnVisualScriptingDebugFlow = nullptr; MMethod* Internal_OnAnimGraphDebugFlow = nullptr; +MMethod* Internal_RequestStartPlayOnEditMode = nullptr; void OnLightmapsBake(ShadowsOfMordor::BuildProgressStep step, float stepProgress, float totalProgress, bool isProgressEvent) { @@ -209,7 +210,7 @@ ManagedEditor::~ManagedEditor() void ManagedEditor::Init() { // Note: editor modules should perform quite fast init, any longer things should be done in async during 'editor splash screen time - void* args[2]; + void* args[3]; MClass* mclass = GetClass(); if (mclass == nullptr) { @@ -230,6 +231,12 @@ void ManagedEditor::Init() bool skipCompile = CommandLine::Options.SkipCompile.IsTrue(); args[0] = &isHeadless; args[1] = &skipCompile; + Guid sceneId; + if (!CommandLine::Options.Play.HasValue() || (CommandLine::Options.Play.HasValue() && Guid::Parse(CommandLine::Options.Play.GetValue(), sceneId))) + { + sceneId = Guid::Empty; + } + args[2] = &sceneId; initMethod->Invoke(instance, args, &exception); if (exception) { @@ -481,6 +488,18 @@ bool ManagedEditor::OnAppExit() return MUtils::Unbox(Internal_OnAppExit->Invoke(GetManagedInstance(), nullptr, nullptr)); } +void ManagedEditor::RequestStartPlayOnEditMode() +{ + if (!HasManagedInstance()) + return; + if (Internal_RequestStartPlayOnEditMode == nullptr) + { + Internal_RequestStartPlayOnEditMode = GetClass()->GetMethod("Internal_RequestStartPlayOnEditMode"); + ASSERT(Internal_RequestStartPlayOnEditMode); + } + Internal_RequestStartPlayOnEditMode->Invoke(GetManagedInstance(), nullptr, nullptr); +} + void ManagedEditor::OnEditorAssemblyLoaded(MAssembly* assembly) { ASSERT(!HasManagedInstance()); diff --git a/Source/Editor/Managed/ManagedEditor.h b/Source/Editor/Managed/ManagedEditor.h index 5e0b612b5..df05e87bd 100644 --- a/Source/Editor/Managed/ManagedEditor.h +++ b/Source/Editor/Managed/ManagedEditor.h @@ -133,6 +133,11 @@ public: /// True if exit engine, otherwise false. bool OnAppExit(); + /// + /// Requests play mode when the editor is in edit mode ( once ). + /// + void RequestStartPlayOnEditMode(); + private: void OnEditorAssemblyLoaded(MAssembly* assembly); diff --git a/Source/Engine/Engine/CommandLine.cpp b/Source/Engine/Engine/CommandLine.cpp index d6c03b070..9f5078c64 100644 --- a/Source/Engine/Engine/CommandLine.cpp +++ b/Source/Engine/Engine/CommandLine.cpp @@ -102,6 +102,23 @@ bool CommandLine::Parse(const Char* cmdLine) *(end - len) = 0; \ end -= len; \ } + +#define PARSE_ARG_OPT_SWITCH(text, field) \ + pos = (Char*)StringUtils::FindIgnoreCase(buffer.Get(), TEXT(text)); \ + if (pos) \ + { \ + len = ARRAY_COUNT(text) - 1; \ + if (ParseArg(pos + len, argStart, argEnd)) \ + Options.field = String::Empty; \ + else \ + { \ + Options.field = String(argStart, static_cast(argEnd - argStart)); \ + len = static_cast((argEnd - pos) + 1); \ + Platform::MemoryCopy(pos, pos + len, (end - pos - len) * 2); \ + *(end - len) = 0; \ + end -= len; \ + } \ + } PARSE_BOOL_SWITCH("-windowed ", Windowed); PARSE_BOOL_SWITCH("-fullscreen ", Fullscreen); @@ -137,6 +154,7 @@ bool CommandLine::Parse(const Char* cmdLine) PARSE_ARG_SWITCH("-build ", Build); PARSE_BOOL_SWITCH("-skipcompile ", SkipCompile); PARSE_BOOL_SWITCH("-shaderdebug ", ShaderDebug); + PARSE_ARG_OPT_SWITCH("-play ", Play); #endif diff --git a/Source/Engine/Engine/CommandLine.h b/Source/Engine/Engine/CommandLine.h index 62b38ca99..d9d3547d3 100644 --- a/Source/Engine/Engine/CommandLine.h +++ b/Source/Engine/Engine/CommandLine.h @@ -164,6 +164,11 @@ public: /// Nullable ShaderDebug; + /// + /// -play !guid! ( Scene to play, can be empty to use default ) + /// + Nullable Play; + #endif }; diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp index dddbd6a3e..35b5fe5fb 100644 --- a/Source/Engine/Graphics/Models/Mesh.cpp +++ b/Source/Engine/Graphics/Models/Mesh.cpp @@ -363,7 +363,8 @@ void Mesh::GetDrawCallGeometry(DrawCall& drawCall) const void Mesh::Render(GPUContext* context) const { - ASSERT(IsInitialized()); + if (!IsInitialized()) + return; context->BindVB(ToSpan((GPUBuffer**)_vertexBuffers, 3)); context->BindIB(_indexBuffer); @@ -372,7 +373,7 @@ void Mesh::Render(GPUContext* context) const void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, const Matrix& world, StaticFlags flags, bool receiveDecals, DrawPass drawModes, float perInstanceRandom) const { - if (!material || !material->IsSurface()) + if (!material || !material->IsSurface() || !IsInitialized()) return; // Submit draw call