SimpleAI
 All Classes Namespaces Files Functions Variables Typedefs Macros Groups Pages
LUATreeLoader.h
Go to the documentation of this file.
1 
36 #pragma once
37 
39 #include "tree/TreeNodeImpl.h"
40 #include "AIRegistry.h"
42 #include "tree/TreeNodeParser.h"
43 #include "common/LUA.h"
44 
45 namespace ai {
46 
51 private:
52  class LUATree;
53 
54  class LUACondition {
55  private:
56  const ConditionPtr& _condition;
57  public:
58  LUACondition(const ConditionPtr& condition) :
59  _condition(condition) {
60  }
61 
62  inline const ConditionPtr& getCondition() const {
63  return _condition;
64  }
65  };
66 
67  class LUANode {
68  private:
69  TreeNodePtr _node;
70  LUACondition *_condition;
71  std::vector<LUANode*> _children;
72  LUATree *_tree;
73  const IAIFactory& _aiFactory;
74  public:
75  LUANode(const TreeNodePtr& node, LUATree *tree, const IAIFactory& aiFactory) :
76  _node(node), _condition(nullptr), _tree(tree), _aiFactory(aiFactory) {
77  }
78 
79  ~LUANode() {
80  delete _condition;
81  }
82 
83  inline const IAIFactory& getAIFactory() const{
84  return _aiFactory;
85  }
86 
87  inline TreeNodePtr& getTreeNode() {
88  return _node;
89  }
90 
91  inline const TreeNodePtr& getTreeNode() const {
92  return _node;
93  }
94 
95  inline void setCondition(LUACondition *condition) {
96  _condition = condition;
97  _node->setCondition(condition->getCondition());
98  }
99 
100  inline const std::vector<LUANode*>& getChildren() const {
101  return _children;
102  }
103 
104  inline LUACondition* getCondition() const {
105  return _condition;
106  }
107 
108  LUANode* addChild (const std::string& nodeType, const TreeNodeFactoryContext& ctx) {
109  TreeNodeParser parser(_aiFactory, nodeType);
110  const TreeNodePtr& child = parser.getTreeNode(ctx.name);
111  if (!child) {
112  return nullptr;
113  }
114  LUANode *node = new LUANode(child, _tree, _aiFactory);
115  _children.push_back(node);
116  _node->addChild(child);
117  return node;
118  }
119  };
120 
121  class LUATree {
122  private:
123  std::string _name;
124  LUATreeLoader* _ctx;
125  LUANode* _root;
126  public:
127  LUATree(const std::string& name, LUATreeLoader* ctx) :
128  _name(name), _ctx(ctx), _root(nullptr) {
129  }
130 
131  inline const IAIFactory& getAIFactory() const{
132  return _ctx->getAIFactory();
133  }
134 
135  inline bool setRoot(LUANode* root) {
136  if (_ctx->addTree(_name, root->getTreeNode())) {
137  _root = root;
138  return true;
139  }
140 
141  return false;
142  }
143 
144  inline const std::string& getName() const {
145  return _name;
146  }
147 
148  inline LUANode* getRoot() const {
149  return _root;
150  }
151  };
152 
153  static LUATreeLoader* luaGetContext(lua_State * l) {
154  return lua::LUA::getGlobalData<LUATreeLoader>(l, "Loader");
155  }
156 
157  static LUATree* luaGetTreeContext(lua_State * l, int n) {
158  return lua::LUA::getUserData<LUATree>(l, n, "Tree");
159  }
160 
161  static LUANode* luaGetNodeContext(lua_State * l, int n) {
162  return lua::LUA::getUserData<LUANode>(l, n, "Node");
163  }
164 
165  #if 0
166  static LUACondition* luaGetConditionContext(lua_State * l, int n) {
167  return lua::LUA::getUserData<LUACondition>(l, n, "Condition");
168  }
169  #endif
170 
171  static int luaMain_CreateTree(lua_State * l) {
172  LUATreeLoader *ctx = luaGetContext(l);
173  const std::string name = luaL_checkstring(l, 1);
174  lua::LUA::newUserdata<LUATree>(l, "Tree", new LUATree(name, ctx));
175  return 1;
176  }
177 
178  static int luaTree_GC(lua_State * l) {
179  LUATree *tree = luaGetTreeContext(l, 1);
180  delete tree;
181  return 0;
182  }
183 
184  static int luaTree_ToString(lua_State * l) {
185  const LUATree *tree = luaGetTreeContext(l, 1);
186  lua_pushfstring(l, "tree: %s [%s]", tree->getName().c_str(), tree->getRoot() ? "root" : "no root");
187  return 1;
188  }
189 
190  static int luaTree_GetName(lua_State * l) {
191  const LUATree *tree = luaGetTreeContext(l, 1);
192  lua_pushstring(l, tree->getName().c_str());
193  return 1;
194  }
195 
196  static int luaNode_GC(lua_State * l) {
197  LUANode *node = luaGetNodeContext(l, 1);
198  delete node;
199  return 0;
200  }
201 
202  static int luaNode_ToString(lua_State * l) {
203  const LUANode *node = luaGetNodeContext(l, 1);
204  const LUACondition* condition = node->getCondition();
205  lua_pushfstring(l, "node: %d children [condition: %s]", (int)node->getChildren().size(),
206  condition ? condition->getCondition()->getName().c_str() : "no condition");
207  return 1;
208  }
209 
210  static int luaNode_GetName(lua_State * l) {
211  const LUANode *node = luaGetNodeContext(l, 1);
212  lua_pushstring(l, node->getTreeNode()->getName().c_str());
213  return 1;
214  }
215 
216  static int luaTree_CreateRoot(lua_State * l) {
217  LUATree *ctx = luaGetTreeContext(l, 1);
218  const std::string id = luaL_checkstring(l, 2);
219  const std::string name = luaL_checkstring(l, 3);
220 
221  TreeNodeParser parser(ctx->getAIFactory(), id);
222  const TreeNodePtr& node = parser.getTreeNode(name);
223  if (!node) {
224  return lua::LUA::returnError(l, "Could not create a node for " + id);
225  }
226 
227  LUANode* udata = lua::LUA::newUserdata<LUANode>(l, "Node", new LUANode(node, ctx, ctx->getAIFactory()));
228  if (!ctx->setRoot(udata)) {
229  LUATreeLoader *loader = luaGetContext(l);
230  return lua::LUA::returnError(l, loader->getError());
231  }
232  return 1;
233  }
234 
235  static int luaNode_AddNode(lua_State * l) {
236  LUANode *node = luaGetNodeContext(l, 1);
237  const std::string id = luaL_checkstring(l, 2);
238  const std::string name = luaL_checkstring(l, 3);
239 
240  TreeNodeFactoryContext factoryCtx(name, "", True::get());
241  LUANode* udata = lua::LUA::newUserdata<LUANode>(l, "Node", node->addChild(id, factoryCtx));
242  if (udata == nullptr) {
243  return lua::LUA::returnError(l, "Could not create a node for " + id);
244  }
245  return 1;
246  }
247 
248  static int luaNode_SetCondition(lua_State * l) {
249  LUATreeLoader *ctx = luaGetContext(l);
250  LUANode *node = luaGetNodeContext(l, 1);
251  const std::string conditionExpression = luaL_checkstring(l, 2);
252 
253  ConditionParser parser(ctx->getAIFactory(), conditionExpression);
254  const ConditionPtr& condition = parser.getCondition();
255  if (!condition) {
256  return lua::LUA::returnError(l, "Could not create a condition for " + conditionExpression + ": " + parser.getError());
257  }
258 
259  LUACondition* udata = lua::LUA::newUserdata<LUACondition>(l, "Condition", new LUACondition(condition));
260  node->setCondition(udata);
261  return 1;
262  }
263 
264 public:
265  LUATreeLoader(const IAIFactory& aiFactory) :
266  ITreeLoader(aiFactory) {
267  }
268 
272  bool init(const std::string& luaString) {
273  shutdown();
274 
275  lua::LUA lua;
276  luaL_Reg createTree = { "createTree", luaMain_CreateTree };
277  luaL_Reg eof = { nullptr, nullptr };
278  luaL_Reg funcs[] = { createTree, eof };
279 
280  lua::LUAType tree = lua.registerType("Tree");
281  tree.addFunction("createRoot", luaTree_CreateRoot);
282  tree.addFunction("getName", luaTree_GetName);
283  tree.addFunction("__gc", luaTree_GC);
284  tree.addFunction("__tostring", luaTree_ToString);
285 
286  lua::LUAType node = lua.registerType("Node");
287  node.addFunction("addNode", luaNode_AddNode);
288  node.addFunction("getName", luaNode_GetName);
289  node.addFunction("setCondition", luaNode_SetCondition);
290  node.addFunction("__gc", luaNode_GC);
291  node.addFunction("__tostring", luaNode_ToString);
292 
293  lua.reg("AI", funcs);
294 
295  if (!lua.load(luaString)) {
296  setError("%s", lua.error().c_str());
297  return false;
298  }
299 
300  // loads all the trees
301  lua.newGlobalData<LUATreeLoader>("Loader", this);
302  if (!lua.execute("init")) {
303  setError("%s", lua.error().c_str());
304  return false;
305  }
306 
307  bool empty;
308  {
309  ScopedReadLock scopedLock(_lock);
310  empty = _treeMap.empty();
311  }
312  if (empty) {
313  setError("No behaviour trees specified");
314  return false;
315  }
316  return true;
317  }
318 };
319 
320 }
321 
Implementation of ITreeLoader that gets its data from a lua script.
Definition: LUATreeLoader.h:50
Transforms the string representation of a TreeNode with all its parameters into a TreeNode instance...
Definition: TreeNodeParser.h:22
Context for ITreeNodeFactory.
Definition: AIFactories.h:15
void std::string getError() const
Gives access to the last error state of the ITreeLoader.
Definition: ITreeLoader.h:111
bool execute(const std::string &function, int returnValues=0)
Definition: LUA.h:170
Definition: LUA.h:31
Definition: LUA.h:65
Definition: IAIFactory.h:39
Definition: Thread.h:44
This class must be extended to load behaviour trees. The contract here is that the parsing only happe...
Definition: ITreeLoader.h:24
Transforms the string representation of a condition with all its sub conditions and parameters into a...
Definition: ConditionParser.h:23
bool init(const std::string &luaString)
this will initialize the loader once with all the defined behaviours from the given lua string...
Definition: LUATreeLoader.h:272