xtreampb Posted November 19, 2014 Share Posted November 19, 2014 Hello all, So i have a C++/Lua hybrid project. I would like to access and temporary store data held in a lua script object/entity when a change the map. As this is a C++ project, i have to do my map changes in my C++ back end as my app::Loop is in my C++ source. How would i change maps first off in C++ i know I can set the new map name in my entity using the changemaptrigger script. but that does nothing b/c i'm in a cpp project. I know this isn't well written and seems like rambling. I need to change maps when my character collides with the trigger and i would like that handled in lua. When i change maps i want to retain the character information like health and any other entity (or reference to entity) associated. Quote bool Life() { while(death=false) { if(death==true) return death; } } I have found the secret to infinite life Did I help you out? Like my post! Link to comment Share on other sites More sharing options...
Guppy Posted November 19, 2014 Share Posted November 19, 2014 There are a few solutions, you could use the source from a lua project ( like Crazycarpet suggests here ) world->FindEntity("StorageEntity")->getKeyValue("pauseMouseLook"); expose a C++ 'store/retrieve' function to lua ( I go over some options here that does not require massive external libraries ) #2 only deal with strings so you would have to call it quite a few times Quote System: Linux Mint 17 ( = Ubuntu 14.04 with cinnamon desktop ) Ubuntu 14.04, AMD HD 6850, i5 2500k Link to comment Share on other sites More sharing options...
Crazycarpet Posted November 19, 2014 Share Posted November 19, 2014 Hello all, So i have a C++/Lua hybrid project. I would like to access and temporary store data held in a lua script object/entity when a change the map. As this is a C++ project, i have to do my map changes in my C++ back end as my app::Loop is in my C++ source. How would i change maps first off in C++ i know I can set the new map name in my entity using the changemaptrigger script. but that does nothing b/c i'm in a cpp project. I know this isn't well written and seems like rambling. I need to change maps when my character collides with the trigger and i would like that handled in lua. When i change maps i want to retain the character information like health and any other entity (or reference to entity) associated. Use the Interpreter. Interpreter::NewTable(); Interpreter::SetGlobal(); Interpreter::GetGlobal(); Interpreter::GetTable(); Interpreter::IsTable(); Interpreter::IsFunction(); Interpreter::IsBool(); Interpreter::ToBool(); example from Josh's App.cpp: int stacksize = Interpreter::GetStackSize(); //Get the global error handler function int errorfunctionindex = 0; #ifdef DEBUG Interpreter::GetGlobal("LuaErrorHandler"); errorfunctionindex = Interpreter::GetStackSize(); #endif //Create new table and assign it to the global variable "App" Interpreter::NewTable(); Interpreter::SetGlobal("App"); //Invoke the start script if (!Interpreter::ExecuteFile("Scripts/App.lua")) { System::Print("Error: Failed to execute script \"Scripts/App.lua\"."); return false; } //Call the App:Start() function Interpreter::GetGlobal("App"); if (Interpreter::IsTable()) { Interpreter::PushString("Start"); Interpreter::GetTable(); if (Interpreter::IsFunction()) { Interpreter::PushValue(-2);//Push the app table onto the stack as "self" #ifdef DEBUG errorfunctionindex = -(Interpreter::GetStackSize()-errorfunctionindex+1); #endif if (!Interpreter::Invoke(1,1,errorfunctionindex)) return false; if (Interpreter::IsBool()) { if (!Interpreter::ToBool()) return false; } else { return false; } } } //Restore the stack size Interpreter::SetStackSize(stacksize); As for the map changing, why not use a C++ Derivative of Josh's Lua version? world->Clear(); Time::Pause(); Map::Load("Maps/" + map + ".map"); Time::Resume(); Edit: You'd need to do quite a bit more to take map changing off the Loop so I'd recommend just copying the style of the normal Lua project, It'd be easiest to use a Lua project's App.cpp, App.h and main.cpp files. Quote Link to comment Share on other sites More sharing options...
Rick Posted November 19, 2014 Share Posted November 19, 2014 And that doesn't fail? It's interesting because it used to because if you think about it, your Script:Collision is an entity stored in C++ that has it's function being called (collision in this case)and inside there you are calling a function that is clearing the world, effectively removing all entities (even the entity your script is attached to which should destroy the script object as well that your stack call is currently in). Josh must have added some better error checking in to handle that because generally deleting an object from inside its own function, which is what you're doing, would cause it to crash. This is the reason Josh has the variable. Quote Link to comment Share on other sites More sharing options...
Crazycarpet Posted November 19, 2014 Share Posted November 19, 2014 And that doesn't fail? It's interesting because it used to because if you think about it, your Script:Collision is an entity stored in C++ that has it's function being called (collision in this case)and inside there you are calling a function that is clearing the world, effectively removing all entities (even the entity your script is attached to which should destroy the script object as well that your stack call is currently in). Josh must have added some better error checking in to handle that because generally deleting an object from inside its own function, which is what you're doing, would cause it to crash. This is the reason Josh has the variable. Edit: Hmm, I dropped it into a new project and it does crash, and yeah, it makes sense. I'll try to figure out what I did in my main project to fix it, I totally forgot - this would definitely cause a stack overflow. Edit2: I got home, and you're right Rick: in order to do it I had to use my 'events' library and call an event in the Script which handled everything elsewhere. Edited first post accordingly. Another thing I noticed is I made "ChangeMap" a global, it has to be part of "App" to use "self.world". Quote Link to comment Share on other sites More sharing options...
xtreampb Posted November 20, 2014 Author Share Posted November 20, 2014 ok so this is what i got and it works until i try to access objects creating in my C++ code app.lua --This function will be called once when the program starts function App:Start() --Initialize Steamworks (optional) --Steamworks:Initialize() --Set the application title --[[self.title="MyGame" --Create a window local windowstyle = Window.Titlebar if System:GetProperty("fullscreen")=="1" then windowstyle=windowstyle+Window.FullScreen end self.window=Window:Create(self.title,0,0,System:GetProperty("screenwidth","1024"),System:GetProperty("screenheight","768"),windowstyle) self.window:HideMouse() --Create the graphics context self.context=Context:Create(self.window,0) if self.context==nil then return false end --Create a world self.world=World:Create() self.world:SetLightQuality((System:GetProperty("lightquality","1"))) --Load a map local mapfile = System:GetProperty("map","Maps/start.map") if Map:Load(mapfile)==false then return false end--]] return true end --This is our main program loop and will be called continuously until the program ends function App:Loop() --If window has been closed, end the program --if self.window:Closed() or self.window:KeyDown(Key.Escape) then return false end --Handle map change if changemapname~=nil then --Clear all entities self.world:Clear() --Load the next map Time:Pause() if Map:Load("Maps/"..changemapname..".map")==false then return false end Time:Resume() changemapname = nil end --Update the app timing --Time:Update() --Update the world --self.world:Update() --Render the world --self.world:Render() --Render statistics --[[self.context:SetBlendMode(Blend.Alpha) if DEBUG then self.context:SetColor(1,0,0,1) self.context:DrawText("Debug Mode",2,2) self.context:SetColor(1,1,1,1) self.context:DrawStats(2,22) self.context:SetBlendMode(Blend.Solid) else --Toggle statistics on and off if (self.window:KeyHit(Key.F11)) then self.showstats = not self.showstats end if self.showstats then self.context:SetColor(1,1,1,1) self.context:DrawText("FPS: "..Math:Round(Time:UPS()),2,2) end end]]-- --Refresh the screen --self.context:Sync(true) --Returning true tells the main program to keep looping return true end my C++ code #include "App.h" using namespace Leadwerks; App::App() : window(NULL), context(NULL), world(NULL), camera(NULL) {} App::~App() { delete world; delete window; } bool App::Start() { //Initialize Steamworks (optional) /*if (!Steamworks::Initialize()) { System::Print("Error: Failed to initialize Steam."); return false; }*/ window = Leadwerks::Window::Create("Arena",500,500); context = Context::Create(window); world = World::Create(); window->HideMouse(); std::string mapname = System::GetProperty("map", "Maps/start.map"); Map::Load(mapname); window->SetMousePosition(context->GetWidth() / 2, context->GetHeight() / 2); int stacksize = Interpreter::GetStackSize(); //Get the global error handler function int errorfunctionindex = 0; #ifdef DEBUG Interpreter::GetGlobal("LuaErrorHandler"); errorfunctionindex = Interpreter::GetStackSize(); #endif //Create new table and assign it to the global variable "App" Interpreter::NewTable(); Interpreter::SetGlobal("App"); //Invoke the start script if (!Interpreter::ExecuteFile("Scripts/App.lua")) { System::Print("Error: Failed to execute script \"Scripts/App.lua\"."); return false; } //Call the App:Start() function Interpreter::GetGlobal("App"); if (Interpreter::IsTable()) { Interpreter::PushString("Start"); Interpreter::GetTable(); if (Interpreter::IsFunction()) { Interpreter::PushValue(-2);//Push the app table onto the stack as "self" #ifdef DEBUG errorfunctionindex = -(Interpreter::GetStackSize() - errorfunctionindex + 1); #endif if (!Interpreter::Invoke(1, 1, errorfunctionindex)) return false; if (Interpreter::IsBool()) { if (!Interpreter::ToBool()) return false; } else { return false; } } } //Restore the stack size Interpreter::SetStackSize(stacksize); return true; } bool App::Loop() { if (window->Closed()) return false; if (window->KeyHit(Key::Escape)) return false; //Get the stack size int stacksize = Interpreter::GetStackSize(); //Get the global error handler function int errorfunctionindex = 0; #ifdef DEBUG Interpreter::GetGlobal("LuaErrorHandler"); errorfunctionindex = Interpreter::GetStackSize(); #endif //Call the App:Start() function Interpreter::GetGlobal("App"); if (Interpreter::IsTable()) { Interpreter::PushString("Loop"); Interpreter::GetTable(); if (Interpreter::IsFunction()) { Interpreter::PushValue(-2);//Push the app table onto the stack as "self" #ifdef DEBUG errorfunctionindex = -(Interpreter::GetStackSize() - errorfunctionindex + 1); #endif if (!Interpreter::Invoke(1, 1, errorfunctionindex)) { System::Print("Error: Script function App:Loop() was not successfully invoked."); Interpreter::SetStackSize(stacksize); return false; } if (Interpreter::IsBool()) { if (!Interpreter::ToBool()) { Interpreter::SetStackSize(stacksize); return false; } } else { Interpreter::SetStackSize(stacksize); return false; } } else { System::Print("Error: App:Loop() function not found."); Interpreter::SetStackSize(stacksize); return false; } } else { System::Print("Error: App table not found."); Interpreter::SetStackSize(stacksize); return false; } //Restore the stack size Interpreter::SetStackSize(stacksize); Leadwerks::Time::Update(); world->Update(); world->Render(); context->Sync(true); return true; } what i want to do is be able to access my world object and such from my lua script to change the world as shown in the change world tutorial. In the future i would like to be able to access the entity that caused to collision in my C++ code to retain it between map changes. If not retain the entity itself, then a table of some sort to pass from the entity to the c backend and once the map is loaded, the stored data is used to reconstruct my entity. Quote bool Life() { while(death=false) { if(death==true) return death; } } I have found the secret to infinite life Did I help you out? Like my post! Link to comment Share on other sites More sharing options...
xtreampb Posted November 20, 2014 Author Share Posted November 20, 2014 Got this figured out with the gracious help of our engine creator, Josh. Key Points. Use the global stack. C++ Interpreter::PushObject(your_object_pointer); Interpreter::SetGlobal("global_variable_name_used_in_lua_to_access_previously_pushed_object"); lua self.object=global_variable_name_used_in_lua_to_access_previously_pushed_object --yes the global name is case sensitive the global object can now be used in any script (unless josh comes by and tells us otherwise) 2 Quote bool Life() { while(death=false) { if(death==true) return death; } } I have found the secret to infinite life Did I help you out? Like my post! Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.