This is rather tricky to explain and I could not find anything on this in the documentation or anywhere on the net so I thought this would be a suitable place for this question.
I'm trying to register properties and methods on an object in Lua using C++.
This is what I'm trying to achieve in Lua:
player = createPlayer()
player:jump() // method
player.x = player.x + 3 // properties
I can easily achieve the first line in the example using C++
int create_player(lua_State *L)
{
Player* player = new Player();
..
return 0;
}
int main(int args, char * argv[])
{
lua_State* L = lua_open();
luaL_openlibs(L);
lua_register(L, "createPlayer", create_player);
luaL_dofile(L, "main.lua");
..
return 0;
}
But how do I create the method :jump() and properties .setX and .getX for createPlayer?
What you could have searched is "Binding C++ to Lua".
Since it's a rather popular question, I'll post an answer with a project compilable online:
Starting from a C++ class:
class Player {
int x;
public:
Player() : x(0) {}
int get_x() const { return x; }
void set_x(int x_) { x = x_; }
void jump() {}
};
You can then create bindings using LuaBridge without writing the boilerplate for each of the bound members yourself:
void luabridge_bind(lua_State *L) {
luabridge::getGlobalNamespace(L)
.beginClass<Player>("Player")
.addConstructor<void (*)(), RefCountedPtr<Player> /* shared c++/lua lifetime */ >()
.addProperty("x", &Player::get_x, &Player::set_x)
.addFunction("jump", &Player::jump)
.endClass()
;
}
Using a dedicated Lua State wrapper LuaState, you can then open a Lua state and perform the bindings:
lua::State state;
luabridge_bind(state.getState());
Running the script using some trace output:
try {
static const char *test =
"player = Player() \n"
"player:jump() \n"
"player.x = player.x + 3"
;
state.doString(test);
}
catch (std::exception &e) {
std::cerr << e.what() << std::endl;
}
Produces the following output:
Player
jump
get_x
set_x 3
~Player
You can see the whole thing live at Travis-CI
Related
I'd hate to ask this but I've been trying this for HOURS and I can't figure it out. I'm brand new to C++ and can't figure out why the sprintf_s won't put anything out at the end (or both of them for that matter). Basically, nothing happens in Visual Studio 2019 except the window pops up. I know it's a simple solution but I am going crazy trying to figure it out. Also, do I HAVE to have a main or should it work without it? Ok, also, does my constructor look ok? I have the green squiggly under it and not sure how to fix it or if I can ignore that. I appreciate all the help I can get! Thank you!
//#include "stdafx.h" - commented out as I think this version of VS does
//this automatically (I looked under precompiled headers and it was listed as "Precompiled Header File"
//and it wouldn't work unless I commented it out
#include <iostream>
using namespace std;
// Base Entree class
class Entree
{
protected:
char _entree[10];
public:
const char* getEntree()
{
return _entree;
}
};
// Base Side class
class Side
{
protected:
char _side[10];
public:
char* getSide()
{
return _side;
}
};
class Drink
{
protected:
char _drink[10];
public:
Drink()
{
cout << "\n Fill cup with soda" << endl;
strcpy_s(_drink, "soda");
}
char* getDrink()
{
return _drink;
}
};
// ADDED CODE:
class ComboMeal
{
private:
Entree* entree;
Side* side;
Drink* drink;
char _bag[100];
public:
ComboMeal(const char* type)
{
sprintf_s(_bag, "/n %s meal combo: ", type);
}
void setEntree(Entree * e)
{
entree = e;
}
void setSide(Side * s)
{
side = s;
}
void setDrink(Drink * d)
{
drink = d;
}
const char* openMealBag()
{
sprintf_s(_bag, "%s, %s, %s, %s", _bag, entree->getEntree(), side->getSide(), drink->getDrink());
return _bag;
}
};
int main()
{
}
As it's been said in the comments, in C++ the code that's executed is the one in the main function. Constructors are called when objects of the correspondent class are created, so you should at least have something like this:
int main(){
ComboMeal combo("my type one");
return 0;
}
A more complete example would be:
int main(){
ComboMeal combo("my type one");
combo.setEntree(new Entree);
combo.setSide(new Side);
combo.setDrink(new Drink);
cout << combo.openMealBag() << endl;
return 0;
}
(Of course this will print garbage, because the values within the new objects are not set)
im really stuck right now...
Summary:
My C++ application crashes every time with an
Access Violation Reading Error on location 0x000000008
which must be an error by the use of multiple vectors of object pointers
where the objects are created with the new statement.
-------------
I want to train my skills by creating a simple GUI Engine with SDL2
and designed it like this:
Create Engine class/object with extern (global)
Because i want to pack all Engine related stuff like update functions
in one packet and init this via a init function:
Create GUI class/object with extern
I wanted this to also be in one "pack" and inside this class
i have multiple std::vector <#PointerToObject#> to keep
my created window objects alive on th global heap instead
of creating them temporary is this correct or is there a better
method to do so?
GUI.h
//...
class GUIWindow
{
//...
std::vector< GUIGadgetLable* > _guiGadgetLables;
std::vector< GUIGadgetButton* > _guiGadgetButtons;
//...
};
class GUI
{
//...
std::vector< GUIWindow* > _guiWindows;
//...
void createWindow(std::string title, int x, int y, int sx, int sy);
};
//...
extern GUI engineGUI;
GUI.cpp
//...
void GUI::createWindow(std::string title, int x, int y, int sx, int sy)
{
this->_guiWindows.insert(this->_guiWindows.end(), new GUIWindow(title,x,y,sx,sy));
return this->_guiWindows.at(this->_guiWindows.size()-1);
}
//...
GUI engineGUI;
I do this in many objects and my hirachy for GUI creation is like this:
GUI
1>GUIWindow
2->GUIGadgetLable
3-->GUIText
4--->ResourceTexture (createFromText)
2->GUIImage
3-->ResourceTexture (createFromFile)
2->GUIGadgetButton
3-->GUIText
Everything worked fine till i implemented my ResourceManager to capsule
the SDL texture rendering functions like load a Bitmap from a file into an SDL_Texture and create a texture from a text.
ResourceManager.h
class ResourceFont
{
public:
TTF_Font* _font = NULL;
int _fontSize = 3;
std::string _fontFile = "";
bool loadFromFile(std::string file, int fSize);
void destroy();
};
class ResourceTexture
{
public:
SDL_Texture *_texture = NULL;
SDL_Rect _size;
SDL_Rect _position;
std::string _data = ""; //File/Text
bool _visible = true;
bool _isText = false;
int _fSize = 3;
SDL_Color _textColor = {70,30,120};
bool createFromFile(std::string file, int x, int y, float sx, float sy);
bool createFromText(std::string text, int fSize, int x, int y, SDL_Color foreGround);
bool changeText(std::string text);
void resize(float sx, float sy);
void update(int x, int y);
void draw();
void destroy();
};
class ResourceManager
{
public:
std::vector< ResourceFont* > _resourceFonts;
std::vector< ResourceTexture* > _resourceTextures;
TTF_Font* addFont(std::string fontFile, int fSize);
};
extern ResourceManager engineResource;
The Texture things worked completely but after the implementation of the ResourceFont* Vector and the addFont Function (which uses TTF_Font to create a new font handle for the ResourceTexture::createFromText function) which is below the Program crashes with an access violation reading at adress 0x0...08 and this at the point where i call the
new ResourceFont()
or
return this->_resourceFonts.at(i)->_font;
in my code so i think i got my heap corrupted but i dont know why if everything with the same methods worked well until this point?
ResourceManager.cpp
TTF_Font *ResourceManager::addFont(std::string fontFile, int fSize)
{
std::cout << "GOIN "<< fSize << std::endl;
if (this->_resourceFonts.size())
{
for (unsigned int i=0; i < this->_resourceFonts.size(); i++)
{
std::cout << "Compare: " << i << " Search: " << fSize << " Found: " << this->_resourceFonts.at(i)->_fontSize << std::endl;
if (this->_resourceFonts.at(i)->_fontSize==fSize) //this->_resourceFonts.at(i)->_fontFile==fontFile&&
{
//std::cout << this->_resourceFonts.at(i) << std::endl;
if (this->_resourceFonts.at(i)->_fontSize==fSize)
{
std::cout << "Found one " << &this->_resourceFonts.at(i)->_font << std::endl;
return this->_resourceFonts.at(i)->_font; //Crashes sometimes here were it try to acces the object
}
else
{
return 0;
}
}
std::cout << "Nope" << std::endl;
}
}
std::cout << "Create One" << std::endl << std::endl;
this->_resourceFonts.insert(this->_resourceFonts.end(), new ResourceFont()); //Crashes sometimes here
this->_resourceFonts.at(this->_resourceFonts.size()- 1)->loadFromFile(fontFile,fSize);
if (this->_resourceFonts.at(this->_resourceFonts.size()-1)->_font)
{
return this->_resourceFonts.at(this->_resourceFonts.size()- 1)->_font;
}
else
{
this->_resourceFonts.at(this->_resourceFonts.size()- 1)->destroy();
return NULL;
}
}
Have anybody an idea how to solve this?
Thank you :)
Don't know if this is the real error, but the code is too large to fit in a comment.
At the very end of AddFont you have:
if (this->_resourceFonts.at(this->_resourceFonts.size()-1)->_font)
{
return this->_resourceFonts.at(this->_resourceFonts.size()- 1)->_font;
}
else
{
this->_resourceFonts.at(this->_resourceFonts.size()- 1)->destroy();
return NULL;
}
This code tests for a non-null _font, which means that in the else part the _font member is null. And it is still left in the _resourceFonts vector.
It looks like i found the Problem:
If i use the ResoruceManager::addFont() direct in every function instead of saving it in an extra TTF_Font* var the program runs normal.
Apologies in advance the possibly vague Title, best I could come up with.
I have the following C++ and text file:
cpp file:
class Test
{
int var1;
int var2;
public:
bool set_var1();
bool set_var1();
bool set(string var_name);
void process_file();
}
text file:
var1 value1
var2 value2
Objective - In process_file(), read/parse the text file, and for each varX in file call the corresponding set_varX().
One option, in function set(), compare var_name to "var1" / "var2" / etc, and
call corresponding set_varX(). The issue I have with this approach, as more
lines are added to the text file, the code becomes...ugly, with the long "if-else"
code block in set().
Another option, create a static map
"var1" set_var1()
"var2" set_var2()
set() will iterate over the map, and upon a string compare match call the corresponding func_ptr. This option requires maintaining a map structure.
Though I prefer the second option, less code changes as the test file increases, is there another option. Just thinking out loud, in set(), can I take the string var_name, and prepend set_, and call set_var_name(), basically somehow avoid the string compare, which is done in both the cases above. My gut feeling, in C++, that is not possible to do during runtime
Thank you,
Ahmed.
It sounds like you're asking about reflection, which is not a feature of C++, so this won't be possible. As you pointed out there are solutions to the problem, but all of them will involve a mapping of string names to functions, and you'll have to construct/maintain that mapping yourself. The language won't do this for you.
You can improve option 2 by making var1, var2.. self registering types. New keywords cause no code changes, only new types. Therefor the map has to be some kind of global object, singleton etc.
A very simple example:
struct Setter
{
virtual ~Setter() = default;
virtual void Process(std::string content) const = 0;
};
class SetterMap
{
public:
bool RegisterSetter(std::string keyword, std::unique_ptr<Setter> setter) {
setters[keyword] = move(setter);
return true;
}
const Setter& GetSetter(const std::string& keyword) const {
return *(setters.at(keyword));
}
private:
std::map<std::string, std::unique_ptr<Setter>> setters;
};
inline SetterMap& GetSetterMap() {
static SetterMap map;
return map;
}
Define and register some setters:
struct Var1 : Setter {
void Process(std::string content) const override {
}
};
namespace {
bool var1registered = GetSetterMap().RegisterSetter(
"var1", std::make_unique<Var1>());
}
struct Var2 : Setter {
void Process(std::string content) const override {
}
};
namespace {
bool var2registered = GetSetterMap().RegisterSetter(
"var2", std::make_unique<Var2>());
}
Use the setter map:
int main()
{
std::string line = "var1: blablab";
GetSetterMap().GetSetter("var1").Process(line);
}
Depending on your needs, you might consider embedding Lua and changing the syntax of the text file to something like:
test.var1 = 1234
test.var2 = 42
Here, test would be a global Lua table that you instantiate from the C++ side and assign a metatable to using lua_setmetatable(). The metatable would have a __newindex method as described here. If you're familiar with Python, this is sort of like providing a __setattr__ metamethod—i.e., it intercepts assignment of non-existent fields and executes some user-specified magic.
The 'trick' in your case is to create a metatable in Lua that re-routes access to the var1, var2, etc. fields of test to a lua_CFunction wrapper that sets the corresponding field on the underlying Test object. After that, you can simply 'run' the file using luaL_dofile().
A quick-n-dirty example (tested against Lua 5.1.5) that illustrates the gist of the idea is appended below. (It needs to be compiled with -std=c++11 due to the use of a raw string literal.)
This approach is certainly overkill if your needs are very specific/targeted. However, if you want/need scripting in your app, anyway, embedding Lua is a great solution.
NOTE: It is not strictly required to use a separate table (e.g., test in the example). Lua stores global variables in a table named _G, so you could instead set a metatable for _G. However, doing so is a bit of a hack; it makes the example harder to follow, and would limit some of the other ways you can use Lua in your host application.
#include <cassert>
#include <iostream>
#include <string>
#include <cstdlib>
#include <lua.hpp>
static const char* regkey = "Test";
class Test
{
public:
Test();
virtual ~Test();
void set_var1(int value);
void set_var2(int value);
void process_file(std::string const& filepath);
private:
int var1, var2;
lua_State* L_;
};
static int set_var(lua_State* L)
{
// Get the table, key and value
std::string key = lua_tostring(L, 1);
int value = lua_tointeger(L, 2);
// Get the Test instance pointer from the Lua registry
lua_pushlightuserdata(L, (void*)regkey);
lua_gettable(L, LUA_REGISTRYINDEX);
Test* test = (Test*) lua_touserdata(L, -1);
// Execute set_XXX() as appropriate
if (test == NULL) {
std::cerr << "Pointer in registry is missing or NULL, aborting..."
<< std::endl;
exit(EXIT_FAILURE);
}
if (key == "var1") {
test->set_var1(value);
}
else if (key == "var2") {
test->set_var2(value);
}
else {
std::string errmsg = "No such variable '" + key + "'";
lua_pushstring(L, errmsg.c_str());
lua_error(L);
}
return 0;
}
Test::Test()
{
L_ = luaL_newstate();
assert(L_);
luaL_openlibs(L_);
// Point the Lua global '_set_var' at our C set_var() function
lua_pushcfunction(L_, &set_var);
lua_setglobal(L_, "_set_var");
// Store our `this' pointer in the Lua registry
lua_pushlightuserdata(L_, (void*)regkey);
lua_pushlightuserdata(L_, this);
lua_settable(L_, LUA_REGISTRYINDEX);
// Set up the metatable to re-route "foo = X" to "_set_var('foo', X)"
std::string script = R"SCRIPT(
test = {}
local mt = {}
mt.__newindex = function(tbl, key, value)
_set_var(key, value)
end
setmetatable(test, mt)
)SCRIPT";
int retval = luaL_dostring(L_, script.c_str());
if (retval != 0) {
std::cerr << "luaL_dostring() failed (\""
<< lua_tostring(L_, -1)
<< "\"), aborting..."
<< std::endl;
exit(EXIT_FAILURE);
}
}
Test::~Test()
{
lua_close(L_);
}
void Test::set_var1(int value)
{
std::cout << "Setting var1 to " << value << std::endl;
var1 = value;
}
void Test::set_var2(int value)
{
std::cout << "Setting var2 to " << value << std::endl;
var2 = value;
}
void Test::process_file(std::string const& filepath)
{
int retval = luaL_dofile(L_, filepath.c_str());
if (retval != 0) {
std::cerr << "luaL_dofile() failed (\""
<< lua_tostring(L_, -1)
<< "\"), aborting..."
<< std::endl;
exit(EXIT_FAILURE);
}
}
int main()
{
Test().process_file("config.ini");
return 0;
}
I've searched but haven't been able to get what I want...
I'm doing a little game. And I got this struct that contains the player details.
struct Player
{
string name;
int level;
int exp;
int hp; // life
int mp; // mana
int shield;
};
And when in the menu, the user chooses to start a new game, it goes to this function:
int StartNewPlayer(string name)
{
Player player;
player.name = name;
player.level = 1;
player.exp = 0;
player.hp = 20;
player.mp = 5;
player.shield = 0;
*pass/return the struct here*
}
Then I have a function that prints the game board, and where I should use the data from the new player struct, for example:
void game_board ()
{
cout << "Hello!" << player.name;
(...)
}
Finally, somewhere in main I have:
int main ()
{
StartNewPlayer(new_game());
game_board();
}
that calls all the functions above.
But I can't figure it out... I tried references, pointers without luck.. I need some help here please...
How about this?
Player StartNewPlayer(string name)
{
Player player;
player.name = name;
player.level = 1;
player.exp = 0;
player.hp = 20;
player.mp = 5;
player.shield = 0;
return player;
}
void game_board(Player player)
{
cout << "Hello!" << player.name;
(...)
}
int main ()
{
Player player = StartNewPlayer(new_game());
game_board(player);
}
Do not create extra copies of the data with complex datatypes by using pass-by-value
Use pointers instead to pass the address of the variable that can be modified in the function. The changes will be reflected in the caller's function as well.
void StartNewPlayer(string name, Player *player)
{
player->name = name;
player->level = 1;
player->exp = 0;
player->hp = 20;
player->mp = 5;
player->shield = 0;
}
void game_board(Player* player)
{
cout << "Hello!" << player->name;
(...)
}
int main ()
{
Player player;
StartNewPlayer(new_game(), &player);
game_board(&player);
}
Alternative using pass-by-reference:
If you're a fan of references, (which is just a clever compiler-trick that makes use of pointers internally again):
void StartNewPlayer(string name, Player& player)
{
player.name = name;
player.level = 1;
player.exp = 0;
player.hp = 20;
player.mp = 5;
player.shield = 0;
}
void game_board(Player& player)
{
cout << "Hello!" << player.name;
(...)
}
int main ()
{
Player player;
StartNewPlayer(new_game(), player);
game_board(player);
}
I would suggest returning a pointer to a Player struct. If you return a "reference" like you are doing right now, it will call the copy constructor of Player which can lead to further complications.
Normally, at the end of StartNewPlayer(...), the Player you declared there will cease to exist as the object scope will end, so when you return it, the c++ compiler gets that you want to keep the object alive and will create a copy for you, invisibly. If you return a pointer to it, you really are returning the object you allocated in your function.
Suppose that you have pointers in your Player structure, such as
struct Player
{
int level;
char* name; //lets assume you did it like that
}
When you are returning the Player, the int will be copied, but the char* will not. ints are easy to handle while char* need all kind of tricky functions like strlen and strncpy. The more complex your Player struct becomes, the more problem you will face by using the default copy constructor.
Another solution would be to declare a copy constructor yourself for the Player struct ( really, you could use classes since they are mostly interchangeable in c++ ).
Player(const Player& p)
{
name = p.name;
level = p.level;
// and so forth
}
So I would use
Player* StartNewPlayer(std::string name)
{
Player* player = new Player();
player->name = name;
player->level = 1;
// snip
return player;
}
At the end of your program, be sure to delete player otherwise you will have a memory leak
It seems like threadsafe in my test code below. Can I use Poco::Logger in a multithreaded program?
static Poco::Logger *pLogger;
class MyRunnable : public Poco::Runnable {
private:
std::string _name;
Poco::Random _rnd;
public:
void setName(std::string name) {
_name = name;
}
void run() {
for (int i=0; i<200; i++) {
pLogger->information("info from: " + _name);
_rnd.seed(_rnd.next(65532) * _name.size());
Poco::Thread::sleep(_rnd.next(13) + 1);
}
}
};
here is test main:
int
main ( int argc, char *argv[] )
{
Poco::Thread thr1, thr2, thr3;
MyRunnable *pMyR1 = new MyRunnable(),
*pMyR2 = new MyRunnable(),
*pMyR3 = new MyRunnable();
pMyR1->setName("r1");
pMyR2->setName("ra2");
pMyR3->setName("runable3");
Poco::FormattingChannel *pFCFile = new Poco::FormattingChannel(new Poco::PatternFormatter("%Y-%m-%d %H:%M:%S.%c %N[%P]:%s: %q:%t"));
pFCFile->setChannel(new Poco::FileChannel("test.log"));
pFCFile->open();
pLogger = &(Poco::Logger::create("FileLogger", pFCFile, Poco::Message::PRIO_INFORMATION));
thr1.start(*pMyR1);
thr2.start(*pMyR2);
thr3.start(*pMyR3);
std::cout << "starting..." << std::endl;
thr1.join();
thr2.join();
thr3.join();
std::cout << "end." << std::endl;
return EXIT_SUCCESS;
} /* ---------- end of function main ---------- */
This question is very old, but I had the same doubt, so looking on the library Forum I found:
http://pocoproject.org/forum/viewtopic.php?f=12&t=1233&p=2681&hilit=logger#p2681
The important quotation is: "The Logger is thread safe regarding the different logging function. If you try to change the Channel connected to a Logger while another thread is currently using the Logger, this may lead to problems."