Lua aspect foundation

This commit is contained in:
Dmitry Kovalenko 2011-06-01 13:47:33 +00:00
parent 184ef0c842
commit b2ce483b71
14 changed files with 337 additions and 28 deletions

View file

@ -103,6 +103,8 @@
<Unit filename="../../src/ai/interface.hpp" />
<Unit filename="../../src/ai/lua/core.cpp" />
<Unit filename="../../src/ai/lua/core.hpp" />
<Unit filename="../../src/ai/lua/lua_object.cpp" />
<Unit filename="../../src/ai/lua/lua_object.hpp" />
<Unit filename="../../src/ai/manager.cpp" />
<Unit filename="../../src/ai/manager.hpp" />
<Unit filename="../../src/ai/registry.cpp" />

View file

@ -130,6 +130,8 @@
<Unit filename="..\..\src\ai\interface.hpp" />
<Unit filename="..\..\src\ai\lua\core.cpp" />
<Unit filename="..\..\src\ai\lua\core.hpp" />
<Unit filename="..\..\src\ai\lua\lua_object.cpp" />
<Unit filename="..\..\src\ai\lua\lua_object.hpp" />
<Unit filename="..\..\src\ai\manager.cpp" />
<Unit filename="..\..\src\ai\manager.hpp" />
<Unit filename="..\..\src\ai\registry.cpp" />

View file

@ -6962,6 +6962,34 @@
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\src\ai\lua\lua_object.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\ai\lua\"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\ai\lua\"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug (fast)|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\ai\lua\"
/>
</FileConfiguration>
</File>
</Filter>
</Filter>
</Filter>
@ -8497,6 +8525,10 @@
RelativePath="..\..\src\ai\lua\core.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\lua\lua_object.hpp"
>
</File>
</Filter>
<Filter
Name="testing"

View file

@ -322,6 +322,7 @@ set(wesnoth-main_SRC
ai/gamestate_observer.cpp
ai/interface.cpp
ai/lua/core.cpp
ai/lua/lua_object.cpp
ai/manager.cpp
ai/registry.cpp
ai/testing.cpp

View file

@ -184,6 +184,7 @@ wesnoth_sources = Split("""
ai/gamestate_observer.cpp
ai/interface.cpp
ai/lua/core.cpp
ai/lua/lua_object.cpp
ai/manager.cpp
ai/registry.cpp
ai/testing.cpp

View file

@ -30,7 +30,7 @@ static lg::log_domain log_ai_aspect("ai/aspect");
#define ERR_AI_ASPECT LOG_STREAM(err, log_ai_aspect)
aspect::aspect(readonly_context &context, const config &cfg, const std::string &id):
valid_(false), valid_variant_(false), cfg_(cfg),
valid_(false), valid_variant_(false), valid_lua_(false), cfg_(cfg),
invalidate_on_turn_start_(cfg["invalidate_on_turn_start"].to_bool(true)),
invalidate_on_tod_change_(cfg["invalidate_on_tod_change"].to_bool(true)),
invalidate_on_gamestate_change_(cfg["invalidate_on_gamestate_change"].to_bool()),
@ -89,6 +89,7 @@ bool aspect::redeploy(const config &cfg, const std::string& /*id*/)
valid_ = false;
valid_variant_ =false;
valid_lua_ = false;
cfg_ = cfg;
invalidate_on_turn_start_ = cfg["invalidate_on_turn_start"].to_bool(true);
invalidate_on_tod_change_ = cfg["invalidate_on_tod_change"].to_bool(true);
@ -148,5 +149,4 @@ known_aspect::~known_aspect()
{
}
} //end of namespace ai

View file

@ -22,6 +22,9 @@
#include "property_handler.hpp"
#include "value_translator.hpp"
#include "../lua/lua_object.hpp"
#include "../lua/core.hpp"
#include "../../scripting/lua.hpp"
#include "../../log.hpp"
@ -47,6 +50,7 @@ public:
{
valid_ = false;
valid_variant_ = false;
valid_lua_ = false;
}
@ -96,6 +100,7 @@ public:
protected:
mutable bool valid_;
mutable bool valid_variant_;
mutable bool valid_lua_;
config cfg_;
bool invalidate_on_turn_start_;
@ -144,6 +149,10 @@ public:
if (!valid_variant_ && valid_ ) {
value_variant_ = boost::shared_ptr<variant>(new variant(variant_value_translator<T>::value_to_variant(this->get())));
valid_variant_ = true;
} else if (!valid_variant_ && valid_lua_) {
value_ = value_lua_->get();
value_variant_ = boost::shared_ptr<variant>(new variant(variant_value_translator<T>::value_to_variant(this->get())));
valid_variant_ = true; // @note: temporary workaround
} else {
assert(valid_variant_);
}
@ -157,15 +166,20 @@ public:
virtual boost::shared_ptr<T> get_ptr() const
{
if (!valid_) {
if (!valid_variant_) {
recalculate();
if (!(valid_variant_ || valid_lua_)) {
recalculate();
}
if (!valid_ && valid_variant_) {
value_ = boost::shared_ptr<T>(new T(variant_value_translator<T>::variant_to_value(get_variant())));
valid_ = true;
} else {
assert(valid_);
if (!valid_ ) {
if (valid_variant_) {
value_ = boost::shared_ptr<T>(new T(variant_value_translator<T>::variant_to_value(get_variant())));
valid_ = true;
} else if (valid_lua_){
value_ = value_lua_->get();
valid_ = true;
} else {
assert(valid_);
}
}
}
return value_;
@ -174,6 +188,7 @@ public:
protected:
mutable boost::shared_ptr<T> value_;
mutable boost::shared_ptr<variant> value_variant_;
mutable boost::shared_ptr< lua_object<T> > value_lua_;
};
@ -380,6 +395,45 @@ protected:
};
template<typename T>
class lua_aspect : public typesafe_aspect<T>
{
public:
lua_aspect(readonly_context &context, const config &cfg, const std::string &id, boost::shared_ptr<lua_ai_context>& l_ctx)
: typesafe_aspect<T>(context, cfg, id)
{
std::string value;
if (cfg.has_attribute("value"))
{
value = cfg["value"].str();
value = "return (" + value + ")";
}
else if (cfg.has_attribute("code"))
{
value = cfg["code"].str();
}
else
{
// error
return;
}
handler_ = boost::shared_ptr<lua_ai_action_handler>(resources::lua_kernel->create_lua_ai_action_handler(value.c_str(), *l_ctx));
}
void recalculate() const
{
this->valid_lua_ = true;
boost::shared_ptr< lua_object<T> > l_obj = boost::shared_ptr< lua_object<T> >(new lua_object<T>());
config c = config();
handler_->handle(c, true, l_obj);
this->value_lua_ = l_obj;
}
private:
boost::shared_ptr<lua_ai_action_handler> handler_;
};
class aspect_factory{
public:
@ -415,7 +469,8 @@ public:
{
}
virtual aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id){
aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id)
{
boost::shared_ptr<ASPECT> _a(new ASPECT(context,cfg,id));
aspect_ptr a = _a;
a->on_create();
@ -423,6 +478,48 @@ public:
}
};
class lua_aspect_factory{
public:
typedef boost::shared_ptr< lua_aspect_factory > factory_ptr;
typedef std::map<std::string, factory_ptr> factory_map;
typedef std::pair<const std::string, factory_ptr> factory_map_pair;
static factory_map& get_list() {
static factory_map *aspect_factories;
if (aspect_factories==NULL) {
aspect_factories = new factory_map;
}
return *aspect_factories;
}
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;
lua_aspect_factory( const std::string &name )
{
factory_ptr ptr_to_this(this);
get_list().insert(make_pair(name,ptr_to_this));
}
virtual ~lua_aspect_factory() {}
};
template<class ASPECT>
class register_lua_aspect_factory : public lua_aspect_factory {
public:
register_lua_aspect_factory( const std::string &name )
: lua_aspect_factory( name )
{
}
aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id, boost::shared_ptr<lua_ai_context>& l_ctx)
{
boost::shared_ptr<ASPECT> _a(new ASPECT(context,cfg,id,l_ctx));
aspect_ptr a = _a;
a->on_create();
return a;
}
};
} //end of namespace ai

View file

@ -22,12 +22,14 @@
#include "engine_lua.hpp"
#include "rca.hpp"
#include "stage.hpp"
#include "aspect.hpp"
#include "../gamestate_observer.hpp"
#include "../../log.hpp"
#include "../../resources.hpp"
#include "../lua/core.hpp"
#include "../lua/lua_object.hpp"
#include "../../scripting/lua.hpp"
#include "../../util.hpp"
@ -46,6 +48,8 @@ static lg::log_domain log_ai_engine_lua("ai/engine/lua");
#pragma warning(disable:4250)
#endif
typedef boost::shared_ptr< lua_object<int> > lua_int_obj;
class lua_candidate_action_wrapper : public candidate_action {
public:
lua_candidate_action_wrapper( rca_context &context, const config &cfg, lua_ai_context &lua_ai_ctx)
@ -61,20 +65,23 @@ public:
virtual double evaluate()
{
serialized_evaluation_state_ = config();
lua_int_obj l_obj = lua_int_obj(new lua_object<int>());
if (evaluation_action_handler_) {
evaluation_action_handler_->handle(serialized_evaluation_state_, true);
evaluation_action_handler_->handle(serialized_evaluation_state_, true, l_obj);
} else {
return BAD_SCORE;
}
}
return lexical_cast_default<double>(serialized_evaluation_state_["score"],BAD_SCORE);
return *(l_obj->get());
}
virtual void execute()
{
virtual void execute() {
lua_int_obj l_obj = lua_int_obj(new lua_object<int>());
if (execution_action_handler_) {
execution_action_handler_->handle(serialized_evaluation_state_);
execution_action_handler_->handle(serialized_evaluation_state_, false, l_obj);
}
}
@ -111,8 +118,10 @@ public:
virtual bool do_play_stage()
{
gamestate_observer gs_o;
lua_int_obj l_obj = lua_int_obj(new lua_object<int>());
if (action_handler_) {
action_handler_->handle(serialized_evaluation_state_);
action_handler_->handle(serialized_evaluation_state_, false, l_obj);
}
return gs_o.is_gamestate_changed();
@ -183,6 +192,26 @@ void engine_lua::do_parse_stage_from_config( ai_context &context, const config &
}
}
void engine_lua::do_parse_aspect_from_config( const config &cfg, const std::string &id, std::back_insert_iterator<std::vector< aspect_ptr > > b )
{
const std::string aspect_factory_key = id+"*lua_aspect"; // @note: factory key for a lua_aspect
lua_aspect_factory::factory_map::iterator f = lua_aspect_factory::get_list().find(aspect_factory_key);
if (f == lua_aspect_factory::get_list().end()){
ERR_AI_LUA << "side "<<ai_.get_side()<< " : UNKNOWN aspect["<<aspect_factory_key<<"]" << std::endl;
DBG_AI_LUA << "config snippet contains: " << std::endl << cfg << std::endl;
return;
}
aspect_ptr new_aspect = f->second->get_new_instance(ai_,cfg,id,lua_ai_context_);
if (!new_aspect) {
ERR_AI_LUA << "side "<<ai_.get_side()<< " : UNABLE TO CREATE aspect, key=["<<aspect_factory_key<<"]"<< std::endl;
DBG_AI_LUA << "config snippet contains: " << std::endl << cfg << std::endl;
return;
}
*b = new_aspect;
}
std::string engine_lua::evaluate(const std::string &/*str*/)
{
///@todo this is not mandatory, but if we want to allow lua to evaluate
@ -196,7 +225,6 @@ void engine_lua::set_ai_context(ai_context * /*context*/)
//this function is called when the ai is fully initialized
}
config engine_lua::to_config() const
{
config cfg = engine::to_config();

View file

@ -45,7 +45,13 @@ public:
* and parse several (usually, 1) stages out of it
*/
virtual void do_parse_stage_from_config( ai_context &context, const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b );
/**
* Taka a config (with engine=lua in it)
* and parse several (usually, 1) aspects out of it
*/
void do_parse_aspect_from_config( const config &cfg, const std::string &id, std::back_insert_iterator<std::vector< aspect_ptr > > b );
virtual std::string evaluate(const std::string &str);
/**
@ -59,6 +65,7 @@ public:
* , like access to game state and movement/attack routines.
*/
virtual void set_ai_context(ai_context *context);
private:
/**

View file

@ -28,6 +28,8 @@
#include "core.hpp"
#include "../../scripting/lua.hpp"
#include "../../scripting/lua_api.hpp"
#include "lua_object.hpp" // (Nephro)
#include "../../actions.hpp"
#include "../../attack_prediction.hpp"
@ -52,7 +54,7 @@ static lg::log_domain log_ai_engine_lua("ai/engine/lua");
static char const aisKey = 0;
namespace ai {
void lua_ai_context::init(lua_State *L)
{
// Create the ai elements table.
@ -350,9 +352,9 @@ lua_ai_context::~lua_ai_context()
lua_pop(L, 1);
}
void lua_ai_action_handler::handle(config &cfg, bool configOut)
void lua_ai_action_handler::handle(config &cfg, bool configOut, lua_object_ptr l_obj)
{
int initial_top = lua_gettop(L);//get the old stack size
int initial_top = lua_gettop(L);//get the old stack size
// Load the user function from the registry.
lua_pushlightuserdata(L, (void *)&aisKey);//stack size is now 1 [-1: ais_table key]
@ -369,11 +371,7 @@ void lua_ai_action_handler::handle(config &cfg, bool configOut)
}
else if (luaW_pcall(L, 1, 2, true))
{
int score = lua_tointeger(L, initial_top + 1);
if (!luaW_toconfig(L, initial_top + 2, cfg)) {
ERR_LUA << "Failed to parsed WML object returned by AI function.\n";
}
cfg["score"] = score; // write score to the config
l_obj->store(L, initial_top + 1);
}
lua_settop(L, initial_top);//empty stack

View file

@ -16,13 +16,19 @@
#ifndef AI_LUA_CORE_HPP
#define AI_LUA_CORE_HPP
#include <boost/shared_ptr.hpp>
struct lua_State;
class LuaKernel;
class config;
namespace ai {
class engine_lua;
class lua_object_base;
typedef boost::shared_ptr<lua_object_base> lua_object_ptr;
/**
* Proxy table for the AI context
@ -39,6 +45,9 @@ private:
static lua_ai_context* create(lua_State *L, char const *code, engine_lua *engine);
public:
~lua_ai_context();
lua_ai_context()
{
}
void load();
static void init(lua_State *L);
friend class ::LuaKernel;
@ -60,7 +69,7 @@ private:
static lua_ai_action_handler* create(lua_State *L, char const *code, lua_ai_context &context);
public:
~lua_ai_action_handler();
void handle(config &, bool configOut = false);
void handle(config &, bool configOut, lua_object_ptr);
friend class ::LuaKernel;
};

30
src/ai/lua/lua_object.cpp Normal file
View file

@ -0,0 +1,30 @@
/*
Copyright (C) 2011 by Dmitry Kovalenko <nephro.wes@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* Lua object(code) wrapper implementation
*/
#include "lua_object.hpp"
namespace ai {
lua_object_base::lua_object_base()
{
// empty
}
} //end of namespace ai

97
src/ai/lua/lua_object.hpp Normal file
View file

@ -0,0 +1,97 @@
/*
Copyright (C) 2011 by Dmitry Kovalenko <nephro.wes@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* Lua object(value) wrapper implementation
*/
#ifndef LUA_OBJECT_HPP_INCLUDED
#define LUA_OBJECT_HPP_INCLUDED
#include <string>
#include <boost/shared_ptr.hpp>
#include "lua/lualib.h"
namespace ai {
class lua_object_base {
public:
lua_object_base();
virtual void store(lua_State* L, int n) = 0;
};
template <typename T>
class lua_object : public lua_object_base
{
public:
lua_object()
{
// empty
}
boost::shared_ptr<T> get()
{
return value_;
}
void store(lua_State* L, int n)
{
this->value_ = boost::shared_ptr<T>(to_type(L, n));
}
protected:
// A group of functions that deal with the translation of the results to C++
boost::shared_ptr<T> to_type(lua_State *, int)
{
return boost::shared_ptr<T>();
}
boost::shared_ptr<T> value_;
};
template <>
inline boost::shared_ptr<double> lua_object<double>::to_type(lua_State *L, int n)
{
return boost::shared_ptr<double>(new double(lua_tonumber(L, n)));
}
template <>
inline boost::shared_ptr<std::string> lua_object<std::string>::to_type(lua_State *L, int n)
{
return boost::shared_ptr<std::string>(new std::string(lua_tostring(L, n)));
}
template <>
inline boost::shared_ptr<bool> lua_object<bool>::to_type(lua_State *L, int n)
{
return boost::shared_ptr<bool>(new bool(lua_toboolean(L, n)));
}
template <>
inline boost::shared_ptr<int> lua_object<int>::to_type(lua_State *L, int n)
{
return boost::shared_ptr<int>(new int(lua_tonumber(L, n)));
}
} // end of namespace ai
#endif

View file

@ -357,6 +357,11 @@ static register_aspect_factory< standard_aspect<double> >
static register_aspect_factory< standard_aspect<int> >
villages_per_scout__standard_aspect_factory2("villages_per_scout*");
//name = lua
static register_lua_aspect_factory< lua_aspect<double> >
aggression__lua_aspect_factory("aggression*lua_aspect");
void registry::init()
{
}