BARE2D
LuaScript.cpp
Go to the documentation of this file.
1 #include "LuaScript.hpp"
2 
3 #include "BAREErrors.hpp"
4 
5 #include <lua5.3/lua.hpp>
6 
7 namespace BARE2D {
8 
10  }
11 
13  }
14 
16  }
17 
19  }
20 
21  void LuaScriptContextWrapper::init(lua_State* parentState, LuaScript* script) {
22  // Set the parent state.
23  m_parent = parentState;
24 
25  // Create the self's state, which is actually just a subroutine of the main.
26  createThread();
27 
28  // Load and compile the script, saving it for later.
29  loadLua(script->m_script);
30  }
31 
33  // Create the thread, as a subroutine of the parent - the master state/thread.
34  m_state = lua_newthread(m_parent);
35  // Push the state to the registry of the parent, and return the index
36  m_threadReference = luaL_ref(m_parent, LUA_REGISTRYINDEX);
37 
38  // Make sure that we have no errors.
39  if(m_threadReference == LUA_REFNIL) {
40  m_state = nullptr;
41  throwError(BAREError::LUA_FAILURE, "Failed to create Lua thread");
42  }
43  }
44 
46  m_completed = true;
47  if(m_state) {
48  // Clean the stack
49  lua_settop(m_state, 0);
50  // close and clean the thread
51  lua_close(m_state);
52  m_state = nullptr;
53  }
54  }
55 
57  // To start a Lua script, we need to call lua_callk to allow yielding.
58 
59  // First, to call lua_callk, we need to push the function (which we earlier stored in the registry) to the stack.
60  // Adds registry[m_scriptReference] to the stack.
61  lua_rawgeti(m_state, LUA_REGISTRYINDEX, m_scriptReference);
62 
63  // Then push arguments (of which there are none because it's just an entire script)
64 
65  // Now actually call the function, starting the script.
66  int nargs = 0;
67  // This actually runs the script as a coroutine, so it can be yielded, etc.
68  int errorCode = lua_resume(m_state, nullptr, nargs);
69 
70  // Check if there were any errors
71  if(errorCode != LUA_OK && errorCode != LUA_YIELD) {
72  // There is some error. Throw, and use lua_tostring to get the error string.
74  "Failed to run Lua script: Lua reports: Error code " + std::to_string(errorCode) + " - \'" +
75  lua_tostring(m_state, -1));
76  return; // we're done here.
77  }
78  }
79 
81  // Check if the function is already being delayed
82  if(m_yielded) {
83  // Check if there's still a delay left or if we should resume.
84  if(m_remainingDelay <= 0) {
85  // No delay left, set flags to false and resume
86  m_yielded = false;
87  // Because there was no true "coroutine," it is okay to pass nullptr as the "from" parameter.
88  // Otherwise, resumes the script and replaces exactly 0 things on the stack.
89  lua_resume(m_state, nullptr, 0);
90  } else {
91  // If we still have delay left, just decrement.
93  }
94  } else {
95  // The function is not yielded (!)as far as we know(!)
96  // Check to make sure of this
97  int status = lua_status(m_state);
98 
99  // May as well check for errors
100  if(status != LUA_OK && status != LUA_YIELD) {
101  // Error occurred!
102  throwError(BAREError::LUA_FAILURE, "Lua script crashed partway through!");
103  destroy();
104  return;
105  } else if(status == LUA_YIELD) {
106  // If the status is LUA_YIELD, then its obviously yielded. Obviously the C-side of things doesn't know this yet
107  // So set the stuff we needed to.
108  m_yielded = true;
109  // Get the first thing on the stack - the delay() variable.
110  m_remainingDelay = lua_tointeger(m_state, -1);
111  // And remove from the stack.
112  lua_pop(m_state, 1);
113  } else if(status == LUA_OK) {
114  // This means that the thread is completed
115  m_completed = true;
116  }
117  }
118  }
119 
120  void LuaScriptContextWrapper::loadLua(std::string& luaStr) {
121  // Load the string and collect any error code. Note that this loads the script and pushes it to the stack.
122  int errorCode = luaL_loadstring(m_state, (char*)luaStr.c_str());
123 
124  // Check the error.
125  if(errorCode != LUA_OK) {
126  // There is some error. Throw, and use lua_tostring to get the error string.
128  "Failed to compile Lua string: Lua reports: Error code " + std::to_string(errorCode) + " - \'" +
129  lua_tostring(m_state, -1) + "\'\n\n" + luaStr + "\n\n");
130  // At this point it makes no sense to set the script reference, as the script... doesn't exist.
131  return; // we're done here.
132  }
133 
134  // Now that we've loaded and compiled the script, we need to push it to the registry.
135  // This is a short form of popping from the stack, storing it in the registry, and returning the key.
136  int reference = luaL_ref(m_state, LUA_REGISTRYINDEX);
137  // Set the reference to the index in the registry.
138  m_scriptReference = reference;
139  }
140 
142  return m_completed;
143  }
144 
145 } // namespace BARE2D
BARE2D::LuaScript::m_script
std::string m_script
Definition: LuaScript.hpp:20
BARE2D
Definition: App.cpp:13
BARE2D::LuaScriptContextWrapper::m_parent
lua_State * m_parent
Definition: LuaScript.hpp:78
BARE2D::LuaScript::LuaScript
LuaScript()
Definition: LuaScript.cpp:9
BARE2D::LuaScriptContextWrapper::m_scriptReference
int m_scriptReference
Definition: LuaScript.hpp:88
BARE2D::LuaScript::~LuaScript
~LuaScript()
Definition: LuaScript.cpp:12
BARE2D::LuaScriptContextWrapper::~LuaScriptContextWrapper
~LuaScriptContextWrapper()
Definition: LuaScript.cpp:18
BARE2D::LuaScriptContextWrapper::loadLua
void loadLua(std::string &luaStr)
Loads and compiles the given Lua script. Also, sets m_scriptReference to the index of the compiled sc...
Definition: LuaScript.cpp:120
BARE2D::LuaScriptContextWrapper::start
void start()
Starts the script.
Definition: LuaScript.cpp:56
BARE2D::LuaScriptContextWrapper::m_yielded
bool m_yielded
Definition: LuaScript.hpp:81
BARE2D::LuaScriptContextWrapper::init
void init(lua_State *parentState, LuaScript *script)
Creates and initializes all the necessary bits.
Definition: LuaScript.cpp:21
BARE2D::LuaScriptContextWrapper::update
void update()
Updates the script - decreases delay counter, checks if it is finished, etc.
Definition: LuaScript.cpp:80
BARE2D::LuaScript
Definition: LuaScript.hpp:14
BARE2D::LuaScriptContextWrapper::m_threadReference
int m_threadReference
Definition: LuaScript.hpp:90
BAREErrors.hpp
BARE2D::LuaScriptContextWrapper::isCompleted
bool isCompleted()
Returns m_completed.
Definition: LuaScript.cpp:141
BARE2D::LuaScriptContextWrapper::m_completed
bool m_completed
Definition: LuaScript.hpp:85
BARE2D::throwError
void throwError(BAREError err, std::string message)
Throws an error silently. Adds it to the pile.
Definition: BAREErrors.cpp:190
BARE2D::LuaScriptContextWrapper::LuaScriptContextWrapper
LuaScriptContextWrapper()
Definition: LuaScript.cpp:15
BARE2D::BAREError::LUA_FAILURE
@ LUA_FAILURE
BARE2D::LuaScriptContextWrapper::createThread
void createThread()
Creates the m_state variable as a thread, or subroutine of the parent.
Definition: LuaScript.cpp:32
BARE2D::LuaScriptContextWrapper::m_remainingDelay
unsigned int m_remainingDelay
Definition: LuaScript.hpp:82
BARE2D::LuaScriptContextWrapper::m_state
lua_State * m_state
Definition: LuaScript.hpp:76
BARE2D::LuaScriptContextWrapper::destroy
void destroy()
Cleans up.
Definition: LuaScript.cpp:45
LuaScript.hpp
This is the basic Lua script wrapper - it is what the end-user will create and add to the queue....