Behavior Context, Lua, Passing a table from C++ code to Lua.

0

So im trying to create a SQLite component system with lua interface and im hitting a snag. How do i pass an array to lua from c++?

		int SQLiteSystemComponent::LuaHandler::SqlCallback(void * cbargs, int argc, char **argv, char **azColName) {
int ret;
CallResult(ret, FN_SqlCallback, cbargs, argc, argv, azColName);
return ret;
}

as you can see, i have a "char ** argv" and a "char ** azColName". How would I convert those into tables for lua?

EDIT: Also, how can i have C++ code return multiple returns to lua? I.E.

var1, var2 = EBus.Event.Func(self.entityID, param1)

This would be especially useful for when coders need to provide an error code and data.

asked 7 years ago200 views
5 Answers
0

Hey @REDACTEDUSER

For question 1, I would suggest constructing a vector of supported types (in this case, strings). Like this:

	int SQLiteSystemComponent::LuaHandler::SqlCallback(void * cbargs, int argc, char **argv, char **azColName)
{
int ret;
AZStd::vector<const char*> argvVector(argv, argv + argc);
AZStd::vector<const char*> azColNameVector(azColName, azColName + argc);
CallResult(ret, FN_SqlCallback, cbargs, argvVector, azColNameVector);
return ret;
}

I'm not quite sure about cbargs, that depends on what you plan on passing through there.

As for question two, unfortunately the only way to have bus events return multiple events is with multiple handlers (one return value per handler). This probably isn't what you want. You can, however, provide a global function (or a class member function) with a Lua specific override that returns as many things as you want. For an example of this, see Vector3GetSinCosMultipleReturn in MathReflection.cpp (in AzCore). Keep in mind this will only work for Lua function overrides as ScriptDataContext is a Lua specific class, and you'll need a different approach for other BehaviorContext consumers such as the TrackView, should you choose to support them.

Hope that helps!

Cheers, Colden

answered 7 years ago
0

cbargs is callback args that are passed to the sql callback function from an event:

SQLite.Event.Exec(self.entityId, "sql", cbargs)

argc is the size of the array of both argv and azColName.

EDIT: Also, how to i make a custom struct be available in lua, create a new lua type, or convert a struct to a userdata type?

EDIT2: Doesnt seem to be working right for the vectors...

<00:48:14> Selecting Data.
<00:48:14> First = 0
<00:48:14> Second = FIRST
<00:48:14> cbargs type: userdata
<00:48:14> argc: 2
<00:48:14> argv type: string
<00:48:14> azColName type: string
<00:48:14> i: 1
<00:48:14> i: 2
<00:48:14> First = 1
<00:48:14> Second = SECOND
<00:48:14> cbargs type: userdata
<00:48:14> argc: 2
<00:48:14> argv type: string
<00:48:14> azColName type: string
<00:48:14> i: 1
<00:48:14> i: 2
<00:48:14> First = 2
<00:48:14> Second = THIRD
<00:48:14> cbargs type: userdata
<00:48:14> argc: 2
<00:48:14> argv type: string
<00:48:14> azColName type: string
<00:48:14> i: 1
<00:48:14> i: 2
<00:48:14> 0<br>

SqlCallback lua function:

	function menu:SqlCallback(cbargs, argc, argv, azColName)
Debug.Log("cbargs type: " .. type(cbargs))
Debug.Log("argc: " .. argc)
Debug.Log("argv type: " .. type(argv))
--Debug.Log("argv: " .. argv)
Debug.Log("azColName type: " .. type(azColName))
--Debug.Log("azColName: " .. azColName)
for i=1, argc,1 do
Debug.Log("i: " .. i)
if azColName[i] ~= nil then Debug.Log("azColName: " .. azColName[i]) end
if argv[i] ~= nil then Debug.Log("argv: " .. argv[i]) end
end
return 0
end

SqlCallback Handler Function:

	int SQLiteSystemComponent::LuaHandler::SqlCallback(void * cbargs, int argc, char **argv, char **azColName) {
int ret;
int i;
for (i = 0; i<argc; i++) {
AZ_Printf("SQLite", "%s = %s", azColName[i], argv[i] ? argv[i] : "NULL");
}
AZStd::vector<const char*> argvVector(argv, argv + argc);
AZStd::vector<const char*> azColNameVector(azColName, azColName + argc);
CallResult(ret, FN_SqlCallback, cbargs, argc, argvVector, azColNameVector);
return ret;
}

ExecLua Event Function:

	int SQLiteSystemComponent::ExecLua(const char *sql, void * cbarg) {
typedef struct {
void* cbarg;
AZ::EntityId id;
} ARGS;
ARGS args;
args.cbarg = cbarg;
args.id = this->GetEntityId();
auto callback = [](void* cbarg, int argc, char **argv, char **azColName) -> int {
int ret;
ARGS* args = (ARGS*)cbarg;
SQLite::SQLiteLuaBus::EventResult(ret, args->id, &SQLite::SQLiteLuaBus::Events::SqlCallback, args->cbarg, argc, argv, azColName);
return ret;
};
//char * errmsg = 0;
return sqlite3_exec(
this->m_pDB,
sql,
callback,
&args,
nullptr
);
}

EDIT3: Looking at the the code that I have provided, is it possible to have the SqlCallback provide a key-value table in lua? For the example above, basicly have the lua table:


table = { First = 0, Second = "FIRST" }
table["First"] = 0
table["Second"] = "FIRST"

Which for each call of the SqlCallback would be one row of the sql data that was provided as a key value pair table. So i could have the SqlCallback Lua code be:

	function menu:SqlCallback(cbargs, row)
for k,v in pairs(row) do
Debug.Log(k .." = ".. v)
end
return 0
end

EDIT4: I've been trying various methods of trying to get an array passed to lua but all of it doesnt seem to work. I've tried AZStd::vector<char *>, AZStd::vector<AZStd::pair<char , char>>, AZStd::unordered_map<char *, char *>, and even AZStd::vectorAZStd::string.

All of it did not work. Heck if i just use the vector without making it a pointer it causes the program to error out. And if i do have it as a pointer it makes it a userdata type where i cant even use it.

answered 7 years ago
0

That doesnt help. I can tell that Platform is using behavior contexts and Windows64 is just an enum within the Platform name.

What I need is a way of having a C++ function pass an array as a Lua table in Lua. As it stands, there doesnt seem to be any way of doing this unless im missing something.

answered 7 years ago
0

Hey @alatnet,

Any luck with passing data over to Lua? A userdata type in Lua essentially means it's an undefined block of memory. You will need to define it to properly use it. A good example to follow would be the ScriptSystemComponent.cpp where the PlatformId enum class is exposed as well as properties and any methods that go along with it - allowing you to access it in Lua just like this:

Debug.Log(Platform.GetName(Platform.Current)) -- prints the string version of the current platform
if Platform.Current == Platform.Windows64 then
-- Since the properties are exposed, you can also do comparison checks.
end

Hope that helps,

Thanks!

answered 7 years ago
0

Hello @alatnet,

What version of Lumberyard are you using? In 1.9, AZStd::vector is already handled to be treated as a Lua table and I'm quite positive that in earlier versions that is also the case but I could be wrong. The same goes for AZStd::string.

Technically speaking, it should automatically convert AZStd::vectorAZStd::string to a lua table accessible as a 1-indexed array since both of those class types are registered. Another good example file to check is TransformComponent.cpp where the event GetAllDescendants is exposed to Lua which returns an AZStd::vectorAZ::EntityId and that is being treated as a table in Lua.

answered 7 years ago

This post is closed: Adding new answers, comments, and votes is disabled.