PDA

View Full Version : ScriptedBrain(engine hack)



bullno1
08-04-2008, 12:07 PM
Simply add these 4 files:
ScriptedBrain.h


#ifndef ScriptedBrain_h__
#define ScriptedBrain_h__

#include "Brain.h"
#include "luabind/object.hpp"

class ScriptedBrain: public Brain
{
public:
ScriptedBrain(MovingEntity * pParent, ScriptedBrain* root);
ScriptedBrain(const string& name, luabind::object const& table);
virtual ~ScriptedBrain();

virtual void Update(float step);
virtual const char * GetName();
virtual Brain * CreateInstance(MovingEntity *pParent);
virtual void HandleMsg(const string &msg);
virtual string HandleAskMsg(const string &msg);

private:
ScriptedBrain* root;
luabind::object table;
string name;
};

#endif // ScriptedBrain_h__


ScriptedBrain.cpp

#include "AppPrecomp.h"
#include "ScriptedBrain.h"
#include "MovingEntity.h"
#include "ScriptManager.h"

using namespace luabind;

ScriptedBrain::ScriptedBrain(MovingEntity * pParent, ScriptedBrain* root)
:Brain(pParent),root(root)
{
table=newtable(root->table.interpreter());
for (raw_iterator i(root->table), end; i != end; ++i)
{
table[i.key()]=*i;
}
table["entity"]=pParent;
}

ScriptedBrain::ScriptedBrain(const string& name, luabind::object const& table)
:Brain(NULL),name(name),table(table),root(NULL)
{
RegisterClass();
}

ScriptedBrain::~ScriptedBrain()
{
}

void ScriptedBrain::Update(float step)
{
object func=table["Update"];
if(type(func)==LUA_TFUNCTION)
{
try
{
func(table,step);
}
LUABIND_ENT_BRAIN_CATCH("Error running Update()");
}
}

const char * ScriptedBrain::GetName()
{
if(root)
return root->name.c_str();
else
return name.c_str();
}

Brain * ScriptedBrain::CreateInstance(MovingEntity *pParent)
{
return new ScriptedBrain(pParent,this);//clone the brain
}

void ScriptedBrain::HandleMsg(const string &msg)
{
object func=table["HandleMsg"];
if(type(func)==LUA_TFUNCTION)
{
try
{
func(table,msg);
}
LUABIND_ENT_BRAIN_CATCH("Error running HandleMsg()");
}
}

string ScriptedBrain::HandleAskMsg(const string &msg)
{
object func=table["HandleAskMsg"];
if(type(func)==LUA_TFUNCTION)
{
try
{
func(table,msg);//I still have problem with returning value from luabind
}
LUABIND_ENT_BRAIN_CATCH("Error running HandleAskMsg()");
}
return string();
}

ScriptedBrainBinding.h:

#ifndef ScriptedBrainBindings_HEADER_INCLUDED // include guard
#define ScriptedBrainBindings_HEADER_INCLUDED // include guard

void luabindScriptedBrain(lua_State *pState);

#endif // include guard

ScriptedBrainBinding.cpp

#include "AppPrecomp.h"
#include "ScriptedBrainBindings.h"
#include "ScriptedBrain.h"
#include <set>

#ifndef WIN32
#include <luabind/luabind.hpp>
#include <luabind/operator.hpp>
#endif

using namespace luabind;
static std::set<string> brainNames;//to ensure that we register a brain once since it could be done twice when the engine restarts
void CreateBrain(const string& brainName,object const& table)
{
if(type(table)==LUA_TTABLE)
{
if(brainNames.find(brainName)!=brainNames.end())//If it was not registered before
{
new ScriptedBrain(brainName,table);//The brain will be handled by brainRegistry
brainNames.insert(brainName);
}
}
else
throw std::exception("Param 2 must be table");
}

void luabindScriptedBrain(lua_State *pState)
{
module(pState)
[
def("CreateBrain",&CreateBrain)
];
}

In luabindBindings.cpp, include scriptedBrainBinding.h and call luabindScriptedBrain

How to use:
create a table: eg: brain={}; Define its function like a normal brain in C++ . Currently, only Update, HandleMsg, HandleAskMsg is supported. Call CreateBrain("MyScriptedBrainName",brainTable); Now you can use your scripted brain like C++ brains.

When I finish this(adding more functionality to "my brain"), I might create a svn patch file for convenience.

Some question:
-Which way is better: use a table or use a seperate script file and load it with a ScriptObject(like entities?) . The table method should use less memory, but the scriptObject method is more convenient.
-Currently, I search for the script function everytime a C++ method is called. It would be better if I grab the function since brain creation and use it. However, it would be impossible to "rewrite" the brain ie: brain.Update=//another function. But the concept of brain is actually to add and remove dynamically without changing the brains(since they are the building blocks of logic). Is there a need to override a brain?

I can't wait until I integrate more things in Novashell but exams :(