Application.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <source/Application.h>
  9. #include <source/ApplicationParameters.h>
  10. #include <AzCore/IO/FileIO.h>
  11. #include <AzCore/StringFunc/StringFunc.h>
  12. #include <AzFramework/CommandLine/CommandRegistrationBus.h>
  13. #include <AzToolsFramework/API/EditorPythonRunnerRequestsBus.h>
  14. #include <AzToolsFramework/Asset/AssetUtils.h>
  15. #include <iostream>
  16. #include <string>
  17. namespace PythonBindingsExample
  18. {
  19. //////////////////////////////////////////////////////////////////////////
  20. // Application
  21. Application::Application(int* argc, char*** argv)
  22. : AzToolsFramework::ToolsApplication(argc, argv)
  23. {
  24. }
  25. Application::~Application()
  26. {
  27. TearDown();
  28. }
  29. void Application::SetUp()
  30. {
  31. AZ::Debug::TraceMessageBus::Handler::BusConnect();
  32. AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusConnect();
  33. // prepare the Python binding gem(s)
  34. Start(Descriptor());
  35. AZ::SerializeContext* context = nullptr;
  36. AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
  37. AZ_Assert(context, "Application did not start; detected no serialize context");
  38. AZ_TracePrintf("Python Bindings", "Init() \n");
  39. }
  40. void Application::TearDown()
  41. {
  42. StopPythonVM();
  43. m_showVerboseOutput = false;
  44. AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect();
  45. AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
  46. Stop();
  47. }
  48. void Application::StartPythonVM()
  49. {
  50. auto&& editorPythonEventsInterface = AZ::Interface<AzToolsFramework::EditorPythonEventsInterface>::Get();
  51. if (editorPythonEventsInterface)
  52. {
  53. // already started?
  54. if (m_startedPython == false)
  55. {
  56. m_startedPython = editorPythonEventsInterface->StartPython();
  57. AZ_Error("python_app", m_startedPython, "Python VM did not start.");
  58. }
  59. }
  60. }
  61. void Application::StopPythonVM()
  62. {
  63. auto&& editorPythonEventsInterface = AZ::Interface<AzToolsFramework::EditorPythonEventsInterface>::Get();
  64. if (editorPythonEventsInterface && m_startedPython)
  65. {
  66. editorPythonEventsInterface->StopPython();
  67. m_startedPython = false;
  68. }
  69. else if (m_showVerboseOutput)
  70. {
  71. AZ_Warning("python_app", false, "Python interface could not be stopped.");
  72. }
  73. }
  74. bool Application::Run()
  75. {
  76. ApplicationParameters params;
  77. if (params.Parse(GetCommandLine()))
  78. {
  79. return RunWithParameters(params);
  80. }
  81. return false;
  82. }
  83. bool Application::RunWithParameters(const ApplicationParameters& params)
  84. {
  85. using namespace AzFramework;
  86. using namespace AzToolsFramework;
  87. m_showVerboseOutput = params.m_verbose;
  88. auto&& editorPythonEventsInterface = AZ::Interface<EditorPythonEventsInterface>::Get();
  89. if (editorPythonEventsInterface)
  90. {
  91. try
  92. {
  93. StartPythonVM();
  94. if (!m_startedPython)
  95. {
  96. AZ_Error("python_app", false, "Python VM did not start.");
  97. return false;
  98. }
  99. if (params.m_pythonStatement.empty() == false)
  100. {
  101. EditorPythonRunnerRequestBus::Broadcast(
  102. &EditorPythonRunnerRequestBus::Events::ExecuteByString,
  103. params.m_pythonStatement,
  104. params.m_verbose);
  105. }
  106. if (params.m_pythonFilename.empty() == false)
  107. {
  108. if (m_pythonExceptionCount == 0)
  109. {
  110. RunFileWithArgs(params);
  111. }
  112. else
  113. {
  114. AZ_Warning("python_app", false, "Did not execute script file since statement threw exceptions.");
  115. }
  116. }
  117. const bool errorFree = (m_pythonExceptionCount == 0) && (m_pythonErrorCount == 0);
  118. if (errorFree && params.m_interactiveMode)
  119. {
  120. AZSTD_PRINTF("Interactive mode enabled \n");
  121. std::string statement;
  122. bool executeStatement = false;
  123. do
  124. {
  125. AZSTD_PRINTF("> ");
  126. std::getline(std::cin, statement);
  127. executeStatement = (statement.empty() == false);
  128. if (executeStatement)
  129. {
  130. EditorPythonRunnerRequestBus::Broadcast(
  131. &EditorPythonRunnerRequestBus::Events::ExecuteByString,
  132. statement.c_str(),
  133. params.m_verbose);
  134. }
  135. }
  136. while (executeStatement);
  137. }
  138. if (errorFree == false)
  139. {
  140. AZ_Warning("python_app", false, "Encountered %d exceptions and %d errors", m_pythonExceptionCount, m_pythonErrorCount);
  141. }
  142. return errorFree;
  143. }
  144. catch (const std::exception& e)
  145. {
  146. OnExceptionMessage(e.what());
  147. }
  148. }
  149. else
  150. {
  151. AZ_Error("python_app", false, "Python interface missing. "
  152. "This likely means that the project has not enabled the EditorPythonBindings gem.");
  153. }
  154. return false;
  155. }
  156. bool Application::RunFileWithArgs(const ApplicationParameters& params)
  157. {
  158. using namespace AzFramework;
  159. using namespace AzToolsFramework;
  160. AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
  161. if (fileIO->Exists(params.m_pythonFilename.c_str()) == false)
  162. {
  163. AZ_Error("python_app", false, "Python file (%s) is missing.", params.m_pythonFilename.c_str());
  164. return false;
  165. }
  166. AZStd::vector<AZStd::string_view> pythonArgs;
  167. pythonArgs.reserve(params.m_pythonArgs.size());
  168. for(auto&& arg : params.m_pythonArgs)
  169. {
  170. pythonArgs.push_back(arg);
  171. }
  172. AZStd::transform(params.m_pythonArgs.begin(), params.m_pythonArgs.end(), pythonArgs.begin(), [](auto&& arg)
  173. {
  174. return arg.c_str();
  175. });
  176. EditorPythonRunnerRequestBus::Broadcast(
  177. &EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs,
  178. params.m_pythonFilename,
  179. pythonArgs);
  180. return m_pythonExceptionCount == 0;
  181. }
  182. bool Application::OnPreError(const char* window, const char* fileName, int line, [[maybe_unused]] const char* func, const char* message)
  183. {
  184. printf("\n");
  185. printf("[ERROR] - %s:\n", window);
  186. if (m_showVerboseOutput)
  187. {
  188. printf("(%s - Line %i)\n", fileName, line);
  189. }
  190. printf("%s \n", message);
  191. return true;
  192. }
  193. bool Application::OnPreWarning(const char* window, const char* fileName, int line, [[maybe_unused]] const char* func, const char* message)
  194. {
  195. // remove the warnings about the command line options from AZ::Console
  196. if (AZ::StringFunc::Equal(window, "Az Console"))
  197. {
  198. return true;
  199. }
  200. printf("\n");
  201. printf("[WARN] - %s:\n", window);
  202. if (m_showVerboseOutput)
  203. {
  204. printf("(%s - Line %i)\n", fileName, line);
  205. }
  206. printf("%s \n", message);
  207. return true;
  208. }
  209. bool Application::OnPrintf([[maybe_unused]] const char* window, const char* message)
  210. {
  211. if (m_showVerboseOutput)
  212. {
  213. printf("%s\n", message);
  214. return true;
  215. }
  216. return !m_showVerboseOutput;
  217. }
  218. void Application::OnTraceMessage(AZStd::string_view message)
  219. {
  220. if (m_showVerboseOutput)
  221. {
  222. printf("(python) %.*s \n", aznumeric_cast<int>(message.size()), message.data());
  223. }
  224. }
  225. void Application::OnErrorMessage(AZStd::string_view message)
  226. {
  227. ++m_pythonErrorCount;
  228. printf("(python) [ERROR] %.*s \n", aznumeric_cast<int>(message.size()), message.data());
  229. }
  230. void Application::OnExceptionMessage(AZStd::string_view message)
  231. {
  232. ++m_pythonExceptionCount;
  233. printf("(python) [EXCEPTION] %.*s \n", aznumeric_cast<int>(message.size()), message.data());
  234. }
  235. }