Lua vs C++
Interpreted languages such as lua are never compiled the same way C++ code is, instead it is read by an interpreter which runs the script by calling corresponding machine commands. Something that you may be interested to understand more about how this process works is if you've worked in Visual Studios and you've seen the disassembly of your code which shows your C++ code as if it were in Assembly. Lua has something similar called instruction sets which you can learn more about if you wish but isn't very important to this article.
Okay so why use lua?
As a rule of thumb, if it's gameplay logic do it in lua, if it has to do with the engine then do it in C++. The whole point of using lua is to speed up iteration whether this be gameplay, ui, hud, menus, match making, or anything that requires lots of tweaking. Lua scripts however need to call C++ functions eventually which leads us to the next part.
The cost of transferring data
Wrong. Well right and wrong, C++ is indeed faster however calling a C++ function costs you, and for each argument you pass to the C++ function it also costs you, same thing with getting a return value (which you can get more than one of in lua.)
Instead of using a C++ dot product function we should use a lua dot product function instead, this will significantly faster than having to transfer the data to C++, do the computation, then transfer the result back to lua. Keeping the cost of this transfer in mind when implementing lua into your engine, as well as using lua in your engine is very important since this can quickly slow your game down.
When not to use reflected classes
local dotResult = myVector:dot(otherVector)
I'll probably write a blog post about the specifics of this later since it is very useful.
Using reflected classes and functions in lua is not always the best idea however, a great example of this would be our vector math library. In this case we should write a vector meta class (a meta class is the lua equivalent of a C++ class) as well as a lua vector math library. Then whenever we transfer a vector from C++ to lua we convert it into a lua vector and if we ever transfer it back to C++ we convert it to a C++ vector.
Batching C++ calls
Really big. This means that if we package data together into a single argument instead of multiple arguments we can actually improve our performance. The only downside is our code will probably become annoying to read so we should only ever do this when performance is important, or when you have a specific usage for it. Like batching 500 draw calls from lua to C++ into one.
The big problem in some of our hud code was that we were making hundreds of draw calls from lua to C++ per frame. This meant that we had to jump back and forth between lua and C++ and back which becomes incredibly expensive. A solution to this is to instead load all of the data which we would be sending to C++ into an array, then when we have finished making all of our draw calls we send it all to C++ in one function call.