ai/composite/engine_lua.cpp

Go to the documentation of this file.
00001 /* $Id: engine_lua.cpp 53238 2012-02-25 05:40:07Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2009 - 2012 by Yurii Chernyi <terraninfo@terraninfo.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 /**
00017  * LUA AI Support engine - creating specific ai components from config
00018  * @file
00019  */
00020 
00021 #include "ai.hpp"
00022 #include "engine_lua.hpp"
00023 #include "goal.hpp"
00024 #include "rca.hpp"
00025 #include "stage.hpp"
00026 #include "aspect.hpp"
00027 
00028 #include "../gamestate_observer.hpp"
00029 
00030 #include "../../log.hpp"
00031 #include "../../resources.hpp"
00032 #include "../lua/core.hpp"
00033 #include "../lua/lua_object.hpp"
00034 #include "../../scripting/lua.hpp"
00035 #include "../../util.hpp"
00036 #include "../../unit.hpp"
00037 #include "../../unit_map.hpp"
00038 
00039 
00040 namespace ai {
00041 
00042 static lg::log_domain log_ai_engine_lua("ai/engine/lua");
00043 #define DBG_AI_LUA LOG_STREAM(debug, log_ai_engine_lua)
00044 #define LOG_AI_LUA LOG_STREAM(info, log_ai_engine_lua)
00045 #define WRN_AI_LUA LOG_STREAM(warn, log_ai_engine_lua)
00046 #define ERR_AI_LUA LOG_STREAM(err, log_ai_engine_lua)
00047 
00048 #ifdef _MSC_VER
00049 #pragma warning(push)
00050 //silence "inherits via dominance" warnings
00051 #pragma warning(disable:4250)
00052 #endif
00053 
00054 typedef boost::shared_ptr< lua_object<int> > lua_int_obj;
00055 
00056 class lua_candidate_action_wrapper : public candidate_action {
00057 public:
00058     lua_candidate_action_wrapper( rca_context &context, const config &cfg, lua_ai_context &lua_ai_ctx)
00059         : candidate_action(context,cfg),evaluation_(cfg["evaluation"]),evaluation_action_handler_(),
00060             execution_(cfg["execution"]),execution_action_handler_(),serialized_evaluation_state_()
00061     {
00062         evaluation_action_handler_ = boost::shared_ptr<lua_ai_action_handler>(resources::lua_kernel->create_lua_ai_action_handler(evaluation_.c_str(),lua_ai_ctx));
00063         execution_action_handler_ = boost::shared_ptr<lua_ai_action_handler>(resources::lua_kernel->create_lua_ai_action_handler(execution_.c_str(),lua_ai_ctx));
00064     }
00065 
00066     virtual ~lua_candidate_action_wrapper() {}
00067 
00068 
00069     virtual double evaluate()
00070     {
00071         serialized_evaluation_state_ = config();
00072 
00073         lua_int_obj l_obj = lua_int_obj(new lua_object<int>());
00074 
00075         if (evaluation_action_handler_) {
00076             evaluation_action_handler_->handle(serialized_evaluation_state_, true, l_obj);
00077         } else {
00078             return BAD_SCORE;
00079         }
00080 
00081         return *(l_obj->get());
00082     }
00083 
00084 
00085     virtual void execute()  {
00086         lua_int_obj l_obj = lua_int_obj(new lua_object<int>());
00087         if (execution_action_handler_) {
00088             execution_action_handler_->handle(serialized_evaluation_state_, false, l_obj);
00089         }
00090     }
00091 
00092     virtual config to_config() const
00093     {
00094         config cfg = candidate_action::to_config();
00095         cfg["evaluation"] = evaluation_;
00096         cfg["execution"] = execution_;
00097         cfg.add_child("state",serialized_evaluation_state_);
00098         return cfg;
00099     }
00100 
00101 private:
00102     std::string evaluation_;
00103     boost::shared_ptr<lua_ai_action_handler> evaluation_action_handler_;
00104     std::string execution_;
00105     boost::shared_ptr<lua_ai_action_handler> execution_action_handler_;
00106     config serialized_evaluation_state_;
00107 };
00108 
00109 class lua_sticky_candidate_action_wrapper : public lua_candidate_action_wrapper {
00110 public:
00111     lua_sticky_candidate_action_wrapper( rca_context &context, const config &cfg, lua_ai_context &lua_ai_ctx)
00112         : lua_candidate_action_wrapper(context, cfg, lua_ai_ctx)
00113         , bound_unit_()
00114     {
00115         map_location loc(cfg["unit_x"] - 1, cfg["unit_y"] - 1); // lua and c++ coords differ by one
00116         bound_unit_ = boost::shared_ptr<unit>(new unit(*resources::units->find(loc)));
00117     }
00118 
00119     virtual double evaluate()
00120     {
00121         if (resources::units->find(bound_unit_->underlying_id()).valid())
00122         {
00123             return lua_candidate_action_wrapper::evaluate();
00124         }
00125         else
00126         {
00127             this->set_to_be_removed();
00128             return 0; // Is 0 what we return when we don't want the action to be executed?
00129         }
00130     }
00131 
00132     virtual void execute()
00133     {
00134         lua_candidate_action_wrapper::execute();
00135         this->disable(); // we do not want to execute the same sticky CA twice -> will be moved out to Lua later
00136     }
00137 private:
00138     boost::shared_ptr<unit> bound_unit_;
00139 
00140 };
00141 
00142 class lua_stage_wrapper : public stage {
00143 public:
00144     lua_stage_wrapper( ai_context &context, const config &cfg, lua_ai_context &lua_ai_ctx )
00145         : stage(context,cfg),action_handler_(),code_(cfg["code"]),serialized_evaluation_state_(cfg.child_or_empty("state"))
00146     {
00147         action_handler_ =  boost::shared_ptr<lua_ai_action_handler>(resources::lua_kernel->create_lua_ai_action_handler(code_.c_str(),lua_ai_ctx));
00148     }
00149 
00150     virtual ~lua_stage_wrapper()
00151     {
00152     }
00153 
00154     virtual bool do_play_stage()
00155     {
00156         gamestate_observer gs_o;
00157         lua_int_obj l_obj = lua_int_obj(new lua_object<int>());
00158 
00159         if (action_handler_) {
00160             action_handler_->handle(serialized_evaluation_state_, false, l_obj);
00161         }
00162 
00163         return gs_o.is_gamestate_changed();
00164     }
00165 
00166     virtual config to_config() const
00167     {
00168         config cfg = stage::to_config();
00169         cfg["code"] = code_;
00170         cfg.add_child("state",serialized_evaluation_state_);
00171         return cfg;
00172     }
00173 private:
00174     boost::shared_ptr<lua_ai_action_handler> action_handler_;
00175     std::string code_;
00176     config serialized_evaluation_state_;
00177 };
00178 
00179 
00180 /**
00181  * Note that initially we get access only to readonly context (engine is created rather early, when there's no way to move/attack.
00182  * We inject full ai_context later.
00183  */
00184 engine_lua::engine_lua( readonly_context &context, const config &cfg )
00185     : engine(context,cfg)
00186     , code_(cfg["code"])
00187     , lua_ai_context_(resources::lua_kernel->create_lua_ai_context(
00188         cfg["code"].str().c_str(), this))
00189 {
00190     name_ = "lua";
00191 
00192     config data(cfg.child_or_empty("data"));
00193     lua_ai_context_->set_persistent_data(data);
00194 }
00195 
00196 
00197 engine_lua::~engine_lua()
00198 {
00199 }
00200 
00201 
00202 void engine_lua::do_parse_candidate_action_from_config( rca_context &context, const config &cfg, std::back_insert_iterator<std::vector< candidate_action_ptr > > b ){
00203     if (!cfg) {
00204         return;
00205     }
00206 
00207     if (!lua_ai_context_) {
00208         return;
00209     }
00210 
00211     candidate_action_ptr ca_ptr;
00212     if (!cfg["sticky"].to_bool())
00213     {
00214         ca_ptr = candidate_action_ptr(new lua_candidate_action_wrapper(context,cfg,*lua_ai_context_));
00215     }
00216     else
00217     {
00218         ca_ptr = candidate_action_ptr(new lua_sticky_candidate_action_wrapper(context,cfg,*lua_ai_context_));
00219     }
00220 
00221     if (ca_ptr) {
00222         *b = ca_ptr;
00223     }
00224 }
00225 
00226 void engine_lua::do_parse_stage_from_config( ai_context &context, const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b )
00227 {
00228     if (!cfg) {
00229         return;
00230     }
00231 
00232     if (!lua_ai_context_) {
00233         return;
00234     }
00235 
00236     stage_ptr st_ptr = stage_ptr(new lua_stage_wrapper(context,cfg,*lua_ai_context_));
00237     if (st_ptr) {
00238         st_ptr->on_create();
00239         *b = st_ptr;
00240     }
00241 }
00242 
00243 void engine_lua::do_parse_aspect_from_config( const config &cfg, const std::string &id, std::back_insert_iterator<std::vector< aspect_ptr > > b )
00244 {
00245     const std::string aspect_factory_key = id+"*lua_aspect"; // @note: factory key for a lua_aspect
00246     lua_aspect_factory::factory_map::iterator f = lua_aspect_factory::get_list().find(aspect_factory_key);
00247 
00248     if (f == lua_aspect_factory::get_list().end()){
00249         ERR_AI_LUA << "side "<<ai_.get_side()<< " : UNKNOWN aspect["<<aspect_factory_key<<"]" << std::endl;
00250         DBG_AI_LUA << "config snippet contains: " << std::endl << cfg << std::endl;
00251         return;
00252     }
00253     aspect_ptr new_aspect = f->second->get_new_instance(ai_,cfg,id,lua_ai_context_);
00254     if (!new_aspect) {
00255         ERR_AI_LUA << "side "<<ai_.get_side()<< " : UNABLE TO CREATE aspect, key=["<<aspect_factory_key<<"]"<< std::endl;
00256         DBG_AI_LUA << "config snippet contains: " << std::endl << cfg << std::endl;
00257         return;
00258     }
00259     *b = new_aspect;
00260 }
00261 
00262 void engine_lua::do_parse_goal_from_config(const config &cfg, std::back_insert_iterator<std::vector< goal_ptr > > b )
00263 {
00264     goal_factory::factory_map::iterator f = goal_factory::get_list().find(cfg["name"]);
00265     if (f == goal_factory::get_list().end()){
00266         ERR_AI_LUA << "side "<<ai_.get_side()<< " : UNKNOWN goal["<<cfg["name"]<<"]"<< std::endl;
00267         DBG_AI_LUA << "config snippet contains: " << std::endl << cfg << std::endl;
00268         return;
00269     }
00270     goal_ptr new_goal = f->second->get_new_instance(ai_,cfg);
00271     new_goal->on_create(lua_ai_context_);
00272     if (!new_goal) {
00273         ERR_AI_LUA << "side "<<ai_.get_side()<< " : UNABLE TO CREATE goal["<<cfg["name"]<<"]"<< std::endl;
00274         DBG_AI_LUA << "config snippet contains: " << std::endl << cfg << std::endl;
00275         return;
00276     }
00277     *b = new_goal;
00278 }
00279 
00280 
00281 std::string engine_lua::evaluate(const std::string &/*str*/)
00282 {
00283     ///@todo this is not mandatory, but if we want to allow lua to evaluate
00284     // something 'in context' of this ai, this will be useful
00285     return "";
00286 }
00287 
00288 config engine_lua::to_config() const
00289 {
00290     config cfg = engine::to_config();
00291 
00292     cfg["id"] = get_id();
00293     cfg["code"] = this->code_;
00294 
00295     config data = config();
00296     lua_ai_context_->get_persistent_data(data);
00297     cfg.add_child("data") = data;
00298 
00299     return cfg;
00300 }
00301 
00302 #ifdef _MSC_VER
00303 #pragma warning(pop)
00304 #endif
00305 
00306 } //end of namespace ai
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Thu May 24 2012 01:02:28 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs