LUA - How to interface Bmax Class,method and field

BlitzMax Forums/BlitzMax Beginners Area/LUA - How to interface Bmax Class,method and field

patmaba(Posted 2007) [#1]
Hi,

I'm learning lua with BMAX

I'm interrested to learn how to interface my classe, method and member variables of my bmax class with lua.

i have see an example in cpp. I would like to know how to make the same with bmax

how to make the equivalent in blitzmax for using lua the following function

void RegisterAnimalWithLua(lua_State* pLua)
{
module(pLua)
[
class_<Animal>("Animal")
.def(constructor<string, int>())
.def("Speak", &Animal::Speak)
.def("NumLegs", &Animal::NumLegs)
];
}




Example of lua class :

-- ExposingCPPClassesToLua.lua

--create an animal object and call its methods

cat = Animal("Meow", 4);

print ("\n[Lua]: A cat has "..cat:NumLegs().. " legs.");

cat:Speak();


print ("\n\n----------------------------------------------------");

MyPet = Pet("Scooter", "Meow", 4);

print ("\n[Lua]: My pet is called "..MyPet:GetName());

MyPet:Speak(); 
[\code]

how to define in bmax who are a constructor and animal methods

cat=Animal("Meow", 4);

cat:NumLegs()

cat:Speak();


cpp code : animal.h

#ifndef ANIMAL_H
#define ANIMAL_H

#include <string>
#include <iostream>

----------------------
pet.h

#ifndef PET_H
#define PET_H


#include <string>
#include <iostream>
#include "Animal.h"



class Pet : public Animal
{
private:
  
  std::string  m_Name;

public:

  Pet(std::string name,
      std::string noise,
      int         NumLegs):Animal(noise, NumLegs),
                           m_Name(name)
  {}

  std::string GetName()const{return m_Name;}  
};





#endif 
----------------------
main.cpp 

//include the libraries
#pragma comment(lib, "lua.lib")
#pragma comment(lib, "lualib.lib")
#pragma warning (disable : 4786)

extern "C"
{
  #include <lua.h>
  #include <lualib.h>
  #include <lauxlib.h>
}

#include <string>
#include <iostream>
using namespace std;

//include the luabind headers. Make sure you have the paths set correctly
//to the lua, luabind and Boost files.
#include <luabind/luabind.hpp>
using namespace luabind;

#include "LuaHelperFunctions.h"
#include "Animal.h"
#include "Pet.h"




void RegisterAnimalWithLua(lua_State* pLua)
{
  module(pLua)
  [
    class_<Animal>("Animal")
    .def(constructor<string, int>())
    .def("Speak", &Animal::Speak)
    .def("NumLegs", &Animal::NumLegs)   
  ];  
}

void RegisterPetWithLua(lua_State* pLua)
{
  module(pLua)
    [
      class_<Pet, bases<Animal> >("Pet")
      .def(constructor<string, string, int>())
      .def("GetName", &Pet::GetName)  
    
    ];  
}


int main()
{
  //create a lua state
  lua_State* pLua = lua_open();

  //open the libraries
  OpenLuaLibraries(pLua);

  //open luabind
  open(pLua);

  RegisterAnimalWithLua(pLua);
  RegisterPetWithLua(pLua);
 
  //load and run the script
  RunLuaScript(pLua, "ExposingCPPClassesToLua.lua");

  lua_close(pLua);



  
    
  return 0;
}
class Animal
{
private:
  
  int          m_iNumLegs;

  std::string  m_NoiseEmitted;

public:

  Animal(std::string NoiseEmitted,
         int         NumLegs):m_iNumLegs(NumLegs),
                              m_NoiseEmitted(NoiseEmitted)
  {}

  virtual ~Animal(){}

  virtual void Speak()const
  {std::cout << "\n[C++]: " << m_NoiseEmitted << std::endl;}

  int          NumLegs()const{return m_iNumLegs;}
                                 
};




#endif



note this sample come from excellent book
Programming Game AI by Example
by Mat Buckland ISBN:1556220782
Wordware Publishing © 2005 (495 pages)


Rozek(Posted 2007) [#2]
Mabiz,

if you can wait a few days: I'm currently writing a Lua interface for a whole bunch of BlitzMax modules (including MaxGui, Audio, Sockets, MiniB3D). I'm currently in the state of defining Lua "objects" for the BlitzMax classes, which should be finished by end of this week. After some days of testing and debugging, I should be able to release an alpha version to the public.


patmaba(Posted 2007) [#3]
Rosek,

Great, i'm glad to test your solution.
Do you provide a solution to map custom classes ? If yes, i would like to be the first to test your interface.

Continue and good luck to finish your release.

Patmaba


Rozek(Posted 2007) [#4]
No,

I won't provide an automatism to interface arbitrary BlitzMax types (and I doubt that this would be feasible at runtime without introspection provided by BlitzMax) as I am a complete BlitzMax newbie (really!) and don't have neither the knowledge nor the time to write a parser which builds Lua interfaces from BlitzMax source code...(I leave this as an exercise to the occasional reader ;-) )

My intention is just to build a Lua runtime environment (using BlitzMax) which gives Lua scripts the capability to build GUIs, play Sound, build 3D graphics, access the file system (in a better way than the Lua standard) and do some network communications.

After completion, I will then concentrate on Lua again (and only updating the interface when required)


patmaba(Posted 2007) [#5]
I understand that this exercise of serialisation is difficult with bmax.
However my need is to directly refer my custom blitzmax object in LUA. I did not find how to do this in Blitzmax. I make my first steps with lua on blitzmax. I take part in a game project. I have a real need to code rules through scripts by an interpreter engine. Pro enterprise uses lua. Bmax supports the lua. Therefore, I said myself that it’s the solution of my problem. Currently, I am confronted with the technical problem to refer my classes, method of the class and the member fields of the class bmax in lua. In the code what I did post on the forum, it uses key words modul and .def, what is the equivalent keyword on bmax?
module(pLua)
[
class_<Animal>("Animal")
.def(constructor<string, int>())
.def("Speak", &Animal::Speak)
.def("NumLegs", &Animal::NumLegs) 
]; 
}

If you know the means of how to interfacing a custom blitz class to through lua functions, can you communicate your technique to me to do it. I would be very grateful.

Thank you


Rozek(Posted 2007) [#6]
Patmaba (or Mabiz?)

I do not know C++ (and also refuse to learn it ;-) ), but I can tell you how to work with BlitzMax classes.

First, become familiar with the Lua API - I applied a number of modifications to what is built into BlitzMax, the actual version may be downloaded from my web site (http://www.Andreas-Rozek.de/BlitzMax/lua.mod.zip) Unpack the archive, replace the original module with my version and rebuild the modules - now you will have all you need.

Use of the API is quite straightforward - if you already know it from C, which I assume. Otherwise I would have to explain too much right now.

Apart from string handling (which you don't have to think about, if you

- use ANSI characters only
- never use Strings as some kind of "byte array" (with embedded zeros) under Lua

) the only special "trick" is how to transparently pass BlitzMax objects to and from Lua.

The important keyword is "Handles": create a "handle" for your BlitzMax object (which actually looks like an "int") and pass it as "lightuserdata" to Lua - on its way back, grab the "lightuserdata" from Lua's stack, and reconstruct the BlitzMax object from that handle. An example shall illustrate this:
  lua_pushlightuserdata(LuaState,Byte Ptr(HandleFromObject(...)))

passes an arbitrary object (represented by the ellipsis ...) to Lua.
  TEvent(HandleToObject(int(lua_touserdata(LuaState,StackIndex))))

reconstructs a BlitzMax object (in this example of type TEvent) from Lua userdata grabbed from the stack at position "StackIndex"

Registering a BlitzMax function is also straightforward:
  function BlitzMaxFunction:int (LuaState:Byte Ptr)
    ...
    return 0  ' well, actually this is a "procedure"
  end function

  lua_register(Lua_State, "LuaNameForTheFunction", BlitzMaxFunction)

Within that function, you have full access to all your BlitzMax objects. Just take care of the Lua stack and don't forget to return the number of values your function wants to return to Lua!


Gabriel(Posted 2007) [#7]
Is it necessary to do all te HandleToObject and HandleFromObject stuff? Could you not just cast the object to a byte ptr and the byte ptr to an int?


Rozek(Posted 2007) [#8]
Gabriel,

no, you HAVE to create a Handle for every object in order to "tell" BlitzMax's internal garbage collection that the object is still required. Otherwise, the BlitzMax object might silently be removed from memory some time, let the Lua userdata pointer point to nonsense and lead to strange results.

Of course, if you REALLY know, that your object will survive beause it is already referenced by BlitzMax itself, then you could do without Handles. But be VERY careful!

Personally, I prefer the Handle-based approach and let the Lua garbage collector "release" it as soon as it is no longer needed (using the __gc metamethod and an invocation of a corresponding BlitzMax method)


Rozek(Posted 2007) [#9]
Just as an additional note:

Strings could prinicipally face the same problem when passed to and from Lua: they could silently vanish on either side without letting the other side know, would the Lua API not always copy them already. Thus, be careful when passing large amounts of text to and from Lua - but this is a principal "problem" of the Lua API...


patmaba(Posted 2007) [#10]
Thanks for all information.

HandleToObject and HandleFromObject it's a good idea.

I'll go to test your solution

Patmaba


Mabiz is the name of my game.