ai/composite/aspect.hpp

Go to the documentation of this file.
00001 /* $Id: aspect.hpp 52533 2012-01-07 02:35:17Z 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  * @file
00018  */
00019 
00020 #ifndef AI_COMPOSITE_ASPECT_HPP_INCLUDED
00021 #define AI_COMPOSITE_ASPECT_HPP_INCLUDED
00022 
00023 #include "property_handler.hpp"
00024 #include "value_translator.hpp"
00025 #include "../lua/lua_object.hpp"
00026 #include "../lua/core.hpp"
00027 #include "../../scripting/lua.hpp"
00028 
00029 #include "../../log.hpp"
00030 
00031 #include <boost/bind.hpp>
00032 #include <boost/lexical_cast.hpp>
00033 #include <boost/pointer_cast.hpp>
00034 
00035 #ifdef _MSC_VER
00036 #pragma warning(push)
00037 //silence "inherits via dominance" warnings
00038 #pragma warning(disable:4250)
00039 #endif
00040 
00041 namespace ai {
00042 
00043 class aspect : public readonly_context_proxy, public events::observer, public component {
00044 public:
00045     aspect(readonly_context &context, const config &cfg, const std::string &id);
00046 
00047     virtual ~aspect();
00048 
00049     void invalidate() const
00050     {
00051         valid_ = false;
00052         valid_variant_ = false;
00053         valid_lua_ = false;
00054     }
00055 
00056 
00057     virtual const variant& get_variant() const = 0;
00058 
00059 
00060     virtual boost::shared_ptr<variant> get_variant_ptr() const = 0;
00061 
00062 
00063     virtual void recalculate() const = 0;
00064 
00065 
00066     virtual void on_create();
00067 
00068 
00069     virtual bool redeploy(const config &cfg, const std::string & id);
00070 
00071 
00072     virtual config to_config() const;
00073 
00074 
00075     virtual bool delete_all_facets();
00076 
00077 
00078     void handle_generic_event(const std::string &/*event_name*/)
00079     {
00080         invalidate();
00081     }
00082 
00083 
00084     virtual bool active() const
00085     {
00086         return true;
00087     }
00088 
00089     virtual std::string get_name() const
00090     { return name_; }
00091 
00092     virtual std::string get_id() const
00093     { return id_; }
00094 
00095     virtual std::string get_engine() const
00096     { return engine_; }
00097 
00098     static lg::log_domain& log();
00099 
00100 protected:
00101     mutable bool valid_;
00102     mutable bool valid_variant_;
00103     mutable bool valid_lua_;
00104 
00105     config cfg_;
00106     bool invalidate_on_turn_start_;
00107     bool invalidate_on_tod_change_;
00108     bool invalidate_on_gamestate_change_;
00109     bool invalidate_on_minor_gamestate_change_;
00110     std::string engine_;
00111     std::string name_;
00112     std::string id_;
00113 
00114 };
00115 
00116 template<typename T>
00117 class typesafe_aspect : public aspect {
00118 public:
00119     typesafe_aspect(readonly_context &context, const config &cfg, const std::string &id)
00120         : aspect(context,cfg,id)
00121         , value_()
00122         , value_variant_()
00123         , value_lua_()
00124     {
00125     }
00126 
00127     virtual ~typesafe_aspect()
00128     {
00129     }
00130 
00131 
00132     virtual const T& get() const
00133     {
00134         return *get_ptr();
00135     }
00136 
00137 
00138     virtual const variant& get_variant() const
00139     {
00140         return *get_variant_ptr();
00141     }
00142 
00143     virtual boost::shared_ptr<variant> get_variant_ptr() const
00144     {
00145         if (!valid_variant_) {
00146             if (!valid_) {
00147                 recalculate();
00148             }
00149 
00150             if (!valid_variant_ && valid_ ) {
00151                 value_variant_ = boost::shared_ptr<variant>(new variant(variant_value_translator<T>::value_to_variant(this->get())));
00152                 valid_variant_ = true;
00153             } else if (!valid_variant_ && valid_lua_) {
00154                 value_ = value_lua_->get();
00155                 value_variant_ = boost::shared_ptr<variant>(new variant(variant_value_translator<T>::value_to_variant(this->get())));
00156                 valid_variant_ = true; // @note: temporary workaround
00157             } else {
00158                 assert(valid_variant_);
00159             }
00160         }
00161         return value_variant_;
00162     }
00163 
00164     virtual void recalculate() const = 0;
00165 
00166 
00167     virtual boost::shared_ptr<T> get_ptr() const
00168     {
00169         if (!valid_) {
00170             if (!(valid_variant_ || valid_lua_)) {
00171                 recalculate();
00172             }
00173 
00174             if (!valid_ ) {
00175                 if (valid_variant_) {
00176                     value_ = boost::shared_ptr<T>(new T(variant_value_translator<T>::variant_to_value(get_variant())));
00177                     valid_ = true;
00178                 } else if (valid_lua_){
00179                     value_ = value_lua_->get();
00180                     valid_ = true;
00181                 } else {
00182                     assert(valid_);
00183                 }
00184             }
00185         }
00186         return value_;
00187     }
00188 
00189 protected:
00190     mutable boost::shared_ptr<T> value_;
00191     mutable boost::shared_ptr<variant> value_variant_;
00192     mutable boost::shared_ptr< lua_object<T> > value_lua_;
00193 };
00194 
00195 
00196 class known_aspect {
00197 public:
00198     known_aspect(const std::string &name);
00199 
00200 
00201     virtual ~known_aspect();
00202 
00203 
00204     virtual void set(aspect_ptr a) = 0;
00205 
00206 
00207     virtual void add_facet(const config &cfg) = 0;
00208 
00209 
00210     const std::string& get_name() const;
00211 
00212 protected:
00213     const std::string name_;
00214 };
00215 
00216 
00217 template<class T>
00218 class composite_aspect;
00219 
00220 template<typename T>
00221 class typesafe_known_aspect : public known_aspect {
00222 public:
00223     typesafe_known_aspect(const std::string &name, boost::shared_ptr< typesafe_aspect<T> > &where, aspect_map &aspects)
00224     : known_aspect(name), where_(where), aspects_(aspects)
00225     {
00226     }
00227 
00228     void set(aspect_ptr a)
00229     {
00230         boost::shared_ptr< typesafe_aspect <T> > c = boost::dynamic_pointer_cast< typesafe_aspect<T> >(a);
00231         if (c) {
00232             assert (c->get_id()== this->get_name());
00233             where_ = c;
00234             aspects_.insert(make_pair(this->get_name(),c));
00235         } else {
00236             LOG_STREAM(debug, aspect::log()) << "typesafe_known_aspect [" << this->get_name() << "] : while setting aspect, got null. this might be caused by invalid [aspect] WML" << std::endl;
00237         }
00238     }
00239 
00240     virtual void add_facet(const config &cfg)
00241     {
00242         boost::shared_ptr< composite_aspect <T> > c = boost::dynamic_pointer_cast< composite_aspect<T> >(where_);
00243         if (c) {
00244             assert (c->get_id()==this->get_name());
00245             c->add_facet(-1, cfg);
00246             c->invalidate();
00247         } else {
00248             LOG_STREAM(debug, aspect::log()) << "typesafe_known_aspect [" << this->get_name() << "] : while adding facet to aspect, got null. this might be caused by target [aspect] being not composite" << std::endl;
00249         }
00250     }
00251 
00252 protected:
00253     boost::shared_ptr<typesafe_aspect <T> > &where_;
00254     aspect_map &aspects_;
00255 
00256 };
00257 
00258 
00259 template<typename T>
00260 class composite_aspect : public typesafe_aspect<T> {
00261 public:
00262 
00263     composite_aspect(readonly_context &context, const config &cfg, const std::string &id)
00264         : typesafe_aspect<T>(context, cfg, id)
00265         , facets_()
00266         , default_()
00267     {
00268         foreach (const config &cfg_element, this->cfg_.child_range("facet") ){
00269             add_facet(-1,cfg_element);
00270         }
00271 
00272         const config &_default = this->cfg_.child("default");
00273         if (_default) {
00274             std::vector< aspect_ptr > default_aspects;
00275             engine::parse_aspect_from_config(*this,_default,this->get_id(),std::back_inserter(default_aspects));
00276             if (!default_aspects.empty()) {
00277                 typename aspect_type<T>::typesafe_ptr b = boost::dynamic_pointer_cast< typesafe_aspect<T> >(default_aspects.front());
00278                 default_ = b;
00279             }
00280         }
00281 
00282         boost::function2<void, typename aspect_type<T>::typesafe_ptr_vector&, const config&> factory_facets =
00283                         boost::bind(&ai::composite_aspect<T>::create_facet,*this,_1,_2);
00284 
00285                 register_vector_property(this->property_handlers(),"facet",facets_, factory_facets);
00286 
00287     }
00288 
00289 
00290     void create_facet(  typename aspect_type<T>::typesafe_ptr_vector &facets, const config &cfg)
00291         {
00292         std::vector<aspect_ptr> facets_base;
00293         engine::parse_aspect_from_config(*this,cfg,this->get_id(),std::back_inserter(facets_base));
00294         foreach (aspect_ptr a, facets_base ){
00295             typename aspect_type<T>::typesafe_ptr b = boost::dynamic_pointer_cast< typesafe_aspect<T> > (a);
00296             facets.push_back(b);
00297         }
00298         }
00299 
00300 
00301     virtual void recalculate() const
00302     {
00303         ///@todo 1.9 optimize in case of an aspect which returns variant
00304         foreach (const typename aspect_type<T>::typesafe_ptr &f, make_pair(facets_.rbegin(),facets_.rend())) {
00305             if (f->active()) {
00306                 this->value_ = boost::shared_ptr<T>(f->get_ptr());
00307                 this->valid_ = true;
00308                 return;
00309             }
00310         }
00311         this->value_ = boost::shared_ptr<T>(default_->get_ptr());
00312         this->valid_ = true;
00313     }
00314 
00315 
00316     virtual config to_config() const
00317     {
00318         config cfg = aspect::to_config();
00319         foreach (const typename aspect_type<T>::typesafe_ptr f, facets_) {
00320             cfg.add_child("facet",f->to_config());
00321         }
00322         if (default_) {
00323             cfg.add_child("default",default_->to_config());
00324         }
00325         return cfg;
00326     }
00327 
00328 
00329     virtual bool add_facet(int pos, const config &cfg)
00330     {
00331         if (pos<0) {
00332             pos = facets_.size();
00333         }
00334         std::vector< aspect_ptr > facets;
00335         engine::parse_aspect_from_config(*this,cfg,this->get_id(),std::back_inserter(facets));
00336         int j=0;
00337         foreach (aspect_ptr a, facets ){
00338             typename aspect_type<T>::typesafe_ptr b = boost::dynamic_pointer_cast< typesafe_aspect<T> > (a);
00339             facets_.insert(facets_.begin()+pos+j,b);
00340             j++;
00341         }
00342         return (j>0);
00343     }
00344 
00345 
00346     virtual bool delete_all_facets()
00347     {
00348         bool b = !facets_.empty();
00349         facets_.clear();
00350         return b;
00351     }
00352 
00353 protected:
00354     typename aspect_type<T>::typesafe_ptr_vector facets_;
00355     typename aspect_type<T>::typesafe_ptr default_;
00356 
00357 };
00358 
00359 template<typename T>
00360 class standard_aspect : public typesafe_aspect<T> {
00361 public:
00362     standard_aspect(readonly_context &context, const config &cfg, const std::string &id)
00363         : typesafe_aspect<T>(context, cfg, id), time_of_day_(cfg["time_of_day"]),turns_(cfg["turns"])
00364     {
00365         boost::shared_ptr<T> value(new T(config_value_translator<T>::cfg_to_value(this->cfg_)));
00366         this->value_= value;
00367         LOG_STREAM(debug, aspect::log()) << "standard aspect has time_of_day=["<<time_of_day_<<"], turns=["<<turns_<<"], and value: "<< std::endl << config_value_translator<T>::value_to_cfg(this->get()) << std::endl;
00368     }
00369 
00370 
00371     virtual bool active() const
00372     {
00373         return this->is_active(time_of_day_,turns_);
00374     }
00375 
00376 
00377     void recalculate() const
00378     {
00379         //nothing to recalculate
00380         this->valid_ = true;
00381     }
00382 
00383 
00384     config to_config() const
00385     {
00386         config cfg = aspect::to_config();
00387         config_value_translator<T>::value_to_cfg(this->get(),cfg);
00388         cfg["time_of_day"] = time_of_day_;
00389         cfg["turns"] = turns_;
00390         return cfg;
00391     }
00392 
00393 protected:
00394     std::string time_of_day_;
00395     std::string turns_;
00396 
00397 };
00398 
00399 template<typename T>
00400 class lua_aspect : public typesafe_aspect<T>
00401 {
00402 public:
00403     lua_aspect(readonly_context &context, const config &cfg, const std::string &id, boost::shared_ptr<lua_ai_context>& l_ctx)
00404         : typesafe_aspect<T>(context, cfg, id)
00405         , handler_(), code_()
00406     {
00407         std::string value;
00408         if (cfg.has_attribute("value"))
00409         {
00410             value = cfg["value"].str();
00411             if (value == "yes") /** @todo for Nephro or Crab: get rid of this workaround */
00412             {
00413                 value = "true";
00414             }
00415             value = "return " + value;
00416         }
00417         else if (cfg.has_attribute("code"))
00418         {
00419             value = cfg["code"].str();
00420         }
00421         else
00422         {
00423             // error
00424             return;
00425         }
00426         code_ = value;
00427         handler_ = boost::shared_ptr<lua_ai_action_handler>(resources::lua_kernel->create_lua_ai_action_handler(value.c_str(), *l_ctx));
00428     }
00429 
00430     void recalculate() const
00431     {
00432         this->valid_lua_ = true;
00433         boost::shared_ptr< lua_object<T> > l_obj = boost::shared_ptr< lua_object<T> >(new lua_object<T>());
00434         config c = config();
00435         handler_->handle(c, true, l_obj);
00436         this->value_lua_ = l_obj;
00437     }
00438 
00439     config to_config() const
00440     {
00441         config cfg = aspect::to_config();
00442         cfg["code"] = code_;
00443         return cfg;
00444     }
00445 
00446 private:
00447     boost::shared_ptr<lua_ai_action_handler> handler_;
00448     std::string code_;
00449 };
00450 
00451 
00452 class aspect_factory{
00453 public:
00454     typedef boost::shared_ptr< aspect_factory > factory_ptr;
00455     typedef std::map<std::string, factory_ptr> factory_map;
00456     typedef std::pair<const std::string, factory_ptr> factory_map_pair;
00457 
00458     static factory_map& get_list() {
00459         static factory_map *aspect_factories;
00460         if (aspect_factories==NULL) {
00461             aspect_factories = new factory_map;
00462         }
00463         return *aspect_factories;
00464     }
00465 
00466     virtual aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id) = 0;
00467 
00468     aspect_factory( const std::string &name )
00469     {
00470         factory_ptr ptr_to_this(this);
00471         get_list().insert(make_pair(name,ptr_to_this));
00472     }
00473 
00474     virtual ~aspect_factory() {}
00475 };
00476 
00477 
00478 template<class ASPECT>
00479 class register_aspect_factory : public aspect_factory {
00480 public:
00481     register_aspect_factory( const std::string &name )
00482         : aspect_factory( name )
00483     {
00484     }
00485 
00486     aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id)
00487     {
00488         boost::shared_ptr<ASPECT> _a(new ASPECT(context,cfg,id));
00489         aspect_ptr a = _a;
00490         a->on_create();
00491         return a;
00492     }
00493 };
00494 
00495 class lua_aspect_factory{
00496 public:
00497     typedef boost::shared_ptr< lua_aspect_factory > factory_ptr;
00498     typedef std::map<std::string, factory_ptr> factory_map;
00499     typedef std::pair<const std::string, factory_ptr> factory_map_pair;
00500 
00501     static factory_map& get_list() {
00502         static factory_map *aspect_factories;
00503         if (aspect_factories==NULL) {
00504             aspect_factories = new factory_map;
00505         }
00506         return *aspect_factories;
00507     }
00508 
00509     virtual aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id, boost::shared_ptr<lua_ai_context>& l_ctx) = 0;
00510 
00511     lua_aspect_factory( const std::string &name )
00512     {
00513         factory_ptr ptr_to_this(this);
00514         get_list().insert(make_pair(name,ptr_to_this));
00515     }
00516 
00517     virtual ~lua_aspect_factory() {}
00518 };
00519 
00520 template<class ASPECT>
00521 class register_lua_aspect_factory : public lua_aspect_factory {
00522 public:
00523     register_lua_aspect_factory( const std::string &name )
00524         : lua_aspect_factory( name )
00525     {
00526     }
00527 
00528     aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id, boost::shared_ptr<lua_ai_context>& l_ctx)
00529     {
00530         boost::shared_ptr<ASPECT> _a(new ASPECT(context,cfg,id,l_ctx));
00531         aspect_ptr a = _a;
00532         a->on_create();
00533         return a;
00534     }
00535 };
00536 
00537 
00538 } //end of namespace ai
00539 
00540 #ifdef _MSC_VER
00541 #pragma warning(pop)
00542 #endif
00543 
00544 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Wed May 23 2012 01:02:30 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs