1 #include "AIFramework.h" 2 3 #include "AIClientApp.h" 4 #include "AIWrapper.h" 5 #include "../../universe/BuildingType.h" 6 #include "../../universe/Universe.h" 7 #include "../../util/Directories.h" 8 #include "../../util/Logger.h" 9 #include "../../util/i18n.h" 10 #include "../../util/OptionsDB.h" 11 #include "../../util/ScopedTimer.h" 12 #include "../../Empire/Empire.h" 13 #include "../../Empire/Diplomacy.h" 14 #include "../../python/CommonFramework.h" 15 #include "../../python/SetWrapper.h" 16 #include "../../python/CommonWrappers.h" 17 18 #include <boost/python.hpp> 19 #include <boost/python/suite/indexing/vector_indexing_suite.hpp> 20 #include <boost/python/suite/indexing/map_indexing_suite.hpp> 21 #include <boost/python/docstring_options.hpp> 22 #include <boost/mpl/vector.hpp> 23 #include <boost/python/list.hpp> 24 #include <boost/python/extract.hpp> 25 #include <boost/python/scope.hpp> 26 #include <boost/filesystem.hpp> 27 28 using boost::python::class_; 29 using boost::python::def; 30 using boost::python::return_value_policy; 31 using boost::python::copy_const_reference; 32 using boost::python::reference_existing_object; 33 using boost::python::return_by_value; 34 using boost::python::return_internal_reference; 35 36 using boost::python::vector_indexing_suite; 37 using boost::python::map_indexing_suite; 38 39 using boost::python::object; 40 using boost::python::import; 41 using boost::python::error_already_set; 42 using boost::python::exec; 43 using boost::python::dict; 44 using boost::python::list; 45 using boost::python::extract; 46 47 namespace fs = boost::filesystem; 48 49 BOOST_PYTHON_MODULE(freeOrionAIInterface)50BOOST_PYTHON_MODULE(freeOrionAIInterface) 51 { 52 boost::python::docstring_options doc_options(true, true, false); 53 54 /////////////////// 55 // Game client // 56 /////////////////// 57 FreeOrionPython::WrapAI(); 58 59 ////////////////// 60 // Empire // 61 ////////////////// 62 FreeOrionPython::WrapEmpire(); 63 64 ///////////////////// 65 // UniverseClasses // 66 ///////////////////// 67 FreeOrionPython::WrapUniverseClasses(); 68 FreeOrionPython::WrapGalaxySetupData(); 69 70 /////////////////// 71 // Enums // 72 /////////////////// 73 FreeOrionPython::WrapGameStateEnums(); 74 75 /////////////////// 76 // Config // 77 /////////////////// 78 FreeOrionPython::WrapConfig(); 79 80 //////////////////// 81 // STL Containers // 82 //////////////////// 83 class_<std::vector<int>>("IntVec") 84 .def(vector_indexing_suite<std::vector<int>>()) 85 ; 86 class_<std::vector<std::string>>("StringVec") 87 .def(vector_indexing_suite<std::vector<std::string>>()) 88 ; 89 90 class_<std::map<int, bool>>("IntBoolMap") 91 .def(map_indexing_suite<std::map<int, bool>>()) 92 ; 93 94 FreeOrionPython::SetWrapper<int>::Wrap("IntSet"); 95 FreeOrionPython::SetWrapper<std::string>::Wrap("StringSet"); 96 } 97 98 ////////////////////// 99 // PythonAI // 100 ////////////////////// Initialize()101bool PythonAI::Initialize() { 102 if (PythonBase::Initialize()) { 103 BuildingTypeManager& temp = GetBuildingTypeManager(); // Ensure buildings are initialized 104 (void)temp; // Hide unused variable warning 105 return true; 106 } 107 else 108 return false; 109 } 110 InitImports()111bool PythonAI::InitImports() { 112 DebugLogger() << "Initializing AI Python imports"; 113 // allows the "freeOrionAIInterface" C++ module to be imported within Python code 114 return PyImport_AppendInittab("freeOrionAIInterface", &PyInit_freeOrionAIInterface) != -1; 115 } 116 InitModules()117bool PythonAI::InitModules() { 118 DebugLogger() << "Initializing AI Python modules"; 119 120 // Confirm existence of the directory containing the AI Python scripts 121 // and add it to Pythons sys.path to make sure Python will find our scripts 122 std::string ai_path = boost::filesystem::canonical(GetResourceDir() / GetOptionsDB().Get<std::string>("ai-path")).string(); 123 DebugLogger() << "AI Python script path: " << ai_path; 124 if (!fs::exists(ai_path)) { 125 ErrorLogger() << "Can't find folder containing AI scripts"; 126 return false; 127 } 128 AddToSysPath(ai_path); 129 130 // import universe generator script file 131 m_python_module_ai = import("FreeOrionAI"); 132 133 DebugLogger() << "AI Python modules successfully initialized!"; 134 return true; 135 } 136 GenerateOrders()137void PythonAI::GenerateOrders() { 138 DebugLogger() << "PythonAI::GenerateOrders : initializing turn"; 139 140 ScopedTimer order_timer; 141 try { 142 // call Python function that generates orders for current turn 143 //DebugLogger() << "PythonAI::GenerateOrders : getting generate orders object"; 144 object generateOrdersPythonFunction = m_python_module_ai.attr("generateOrders"); 145 //DebugLogger() << "PythonAI::GenerateOrders : generating orders"; 146 generateOrdersPythonFunction(); 147 } catch (const error_already_set& err) { 148 HandleErrorAlreadySet(); 149 if (!IsPythonRunning() || GetOptionsDB().Get<bool>("testing")) 150 throw; 151 152 ErrorLogger() << "PythonAI::GenerateOrders : Python error caught. Partial orders sent to server"; 153 } 154 155 AIClientApp* app = AIClientApp::GetApp(); 156 // encodes order sets and sends turn orders message. "done" the turn for the client, but "starts" the turn for the server 157 app->StartTurn(app->GetAI()->GetSaveStateString()); 158 159 DebugLogger() << "PythonAI::GenerateOrders order generating time: " << order_timer.DurationString(); 160 } 161 HandleChatMessage(int sender_id,const std::string & msg)162void PythonAI::HandleChatMessage(int sender_id, const std::string& msg) { 163 // call Python function that responds or ignores a chat message 164 object handleChatMessagePythonFunction = m_python_module_ai.attr("handleChatMessage"); 165 handleChatMessagePythonFunction(sender_id, msg); 166 } 167 HandleDiplomaticMessage(const DiplomaticMessage & msg)168void PythonAI::HandleDiplomaticMessage(const DiplomaticMessage& msg) { 169 // call Python function to inform of diplomatic message change 170 object handleDiplomaticMessagePythonFunction = m_python_module_ai.attr("handleDiplomaticMessage"); 171 handleDiplomaticMessagePythonFunction(msg); 172 } 173 HandleDiplomaticStatusUpdate(const DiplomaticStatusUpdateInfo & u)174void PythonAI::HandleDiplomaticStatusUpdate(const DiplomaticStatusUpdateInfo& u) { 175 // call Python function to inform of diplomatic status update 176 object handleDiplomaticStatusUpdatePythonFunction = m_python_module_ai.attr("handleDiplomaticStatusUpdate"); 177 handleDiplomaticStatusUpdatePythonFunction(u); 178 } 179 StartNewGame()180void PythonAI::StartNewGame() { 181 FreeOrionPython::ClearStaticSaveStateString(); 182 // call Python function that sets up the AI to be able to generate orders for a new game 183 object startNewGamePythonFunction = m_python_module_ai.attr("startNewGame"); 184 startNewGamePythonFunction(m_aggression); 185 } 186 ResumeLoadedGame(const std::string & save_state_string)187void PythonAI::ResumeLoadedGame(const std::string& save_state_string) { 188 //DebugLogger() << "PythonAI::ResumeLoadedGame(" << save_state_string << ")"; 189 FreeOrionPython::SetStaticSaveStateString(save_state_string); 190 // call Python function that deals with the new state string sent by the server 191 object resumeLoadedGamePythonFunction = m_python_module_ai.attr("resumeLoadedGame"); 192 resumeLoadedGamePythonFunction(FreeOrionPython::GetStaticSaveStateString()); 193 } 194 GetSaveStateString() const195const std::string& PythonAI::GetSaveStateString() const { 196 // call Python function that serializes AI state for storage in save file and sets s_save_state_string 197 // to contain that string 198 object prepareForSavePythonFunction = m_python_module_ai.attr("prepareForSave"); 199 prepareForSavePythonFunction(); 200 //DebugLogger() << "PythonAI::GetSaveStateString() returning: " << s_save_state_string; 201 return FreeOrionPython::GetStaticSaveStateString(); 202 } 203 SetAggression(int aggr)204void PythonAI::SetAggression(int aggr) 205 { m_aggression = aggr; } 206