Lua preserving global values - c++

I use Lua for my game engine logic. My main game loop is not done in Lua. Only special nodes in my scene hierarchy have Lua scripts attached. These scripts are executed every frame. The problem I face is that I need to keep global variable values from one frame to another.
My temporary solution looks like this:
finish = useBool("finish", false)
timer = useInt("timer", 0)
showTimer = useBool("showTimer", true)
startTimer = useInt("startTimer", 0)
play0 = useBool("play0", false)
play1 = useBool("play1", false)
play2 = useBool("play2", false)
play3 = useBool("play3", false)
delta = useInt("delta", 0)
gameOverTime = useInt("gameOverTime", 5000)
finishTime = useInt("finishTime", 5000)
checkPoint = useInt("checkPoint", 255)
<...> Game logic <...>
setInt("message", message);
setInt("checkPoint", checkPoint)
setInt("finishTime", finishTime)
setInt("gameOverTime", gameOverTime)
setInt("timer", timer)
setBool("play3", play3)
setBool("play2", play2)
setBool("play1", play1)
setBool("play0", play0)
setInt("startTimer", startTimer)
setBool("showTimer", showTimer)
setInt("timer", timer)
setBool("finish", finish);
I call special methods that retrieve global variables from hash maps in C++ at the beginning and I set them again at the end of the script.
Is there a way to do this implicitly?
Is it a bad design to use Lua not as the main game loop?

Well, while there is nothing technically wrong with your solution, you might start to notice some performance issues if you end up with a lot of global variables (something you should, in general, avoid).
With that said, there is room for improvement. For example:
At the beginning of the script, check if your global variable is nil. If it is, then you can initialize it, if not, this is probably not the first time you're running the script, so leave it unmodified. But that means a lot of pesky if-else statements, which one can easily forget about. We can do better!
I would recommend looking at Chapter 14: The Environment, from the Programming in Lua book. Here's a quick quote from the intro:
Lua keeps all its global variables in a regular table, called the environment. ... The other (actually the main) advantage is that we can manipulate this table as any other table. To facilitate such manipulations, Lua stores the environment itself in a global variable _G. (Yes, _G._G is equal to _G.)
Since _G is a table, it also has a metatable, so you can define __index and __newindex metamethods to handle access to and creation of global variables. You can find examples of this in section 14.2. Go read the whole chapter, it's not that long (if you're unfamiliar with metamethods and metatables, also look through chapter 13 - this is where Lua really shines in terms of flexibility).
Now that we've covered the trivial and normal methods, let's look at the overkill end of the spectrum. As an example I'll look at Unity's approach to scripting. A Unity javascript usually defines variables, functions, and types. Any variables defined outside of the scope of methods or types are persisted between frames because the script itself is not executed every frame. Instead, they let the script define functions and call the functions at the appropriate time. So if you want something executed every frame - you put it in the Update function. Every script can define it's own Update function because it has it's own scope. So every frame the scripting engine goes through all objects, checks if the script's scope has an Update method and calls it.
Back to Lua - a solution like this would involve creating separate environments for each object/script/whatever your node is. Then, instead of executing the script attached to your node every frame, your main loop will go through all the nodes and run a function inside of their environment. You can also switch environments, so you can set the global environment to your node's env before executing it, and then switch back when you're done. This allows your scripts to use globals as they see fit, have them persisted between frames and excludes the possibility of name collisions or global namespace pollution. Additionally you can use metamethods to nest the node's environment inside the actual global environment or inside an API environment with helper methods (basically, if __index does not find something it looks it up in a parent).

Related

Saving a "Measurement File" (Trace) while debugging in C++ with GDB

I am facing the following issue: In our project, we have a main class with a main method called "run". This method calls hundreds of other functions, classes etc.
We are now calling this run method in a test in a for loop multiple times, something like that:
for(float test_time = 0; test_time < 10.0; test_time += 0.005){
outputStruct = mainClass.run(inputStruct);
}
I now want to save all local variables of all functions and methods and all member variables of all included objects that are seen when this for loop is executed. And I want to have a snapshot of this for each loop iteration. So in this example, there should be like 2000 snapshots of all my variables.
Is this somehow possible? I see that GDB has some "trace" functionality, but it's not clear for me how I can tell GDB that it should save everything that was "seen" while executing the mainClass.run method. It should "only" remember the last state of each member and local variable. And when test_time increments, it can finalize the current snapshot and create a new one for the next time slot.
Is something like this possible? Since our usecase is some physics based scenario, it is every interesting to see how certain values change over time in a plot later. I don't mind what the format of the output file of GDB is, it will be parsed later anyway, as long as the information is somehow inside. Of course, the cleaner the file looks the better :).
Thank you for your support guys!

Lazy evaluation of Lauterbach macro - is it possible?

I'm currently writing some kind of a "skeleton" for tests to be performed using Lauterbach scripts.
In this skeleton I want to have a part in which all test specific definitions shall be done, e.g. functions to set breaks on, variables to be altered etc. This part shall be just near the top of the script file, so that other users do not have to go through the complete script file, changing values here and there.
Some of the variables that'll be used are defined function-local within the C-code to be tested. So, these become available to the Lauterbach script only once the scope of that function has been entered - which is deeply within the skeleton script code.
Is there a way to define a macro for these variables just way before the scope has been entered?
Let's give some example structure:
LOCAL &funcToTest // the function we want to test
LOCAL &varToBeSet // a variable within the function we want to alter
LOCAL &valueToBeSet // the value we want to set &varToBeSet to
... // some more definitions here
&funcToTest=someFunc
&varToBeSet=status
&valueToBeSet=1
... // some test code following here that sets up log files, screen areas
... // start the program to be tested etc.
IF (Register(PC)==ADDRESS.OFFSET(&funcToTest))
(
// OK - we've hit the breakpoint inside the function to test
... // Run to some point where we can set the local variable
Var.Set &varToBeSet=&valueToBeSet
... // Go on with the program and see what happens - this will be logged
)
The problem is that Lauterbach complains at the line &varToBeSet=status
with Symbol not found in this context - which is correct, because it is a local variable.
Looking at the symbols via View->Symbols->SymbolsTreeView (or by giving the command Symbol.List.Tree) I can find the symbol (in this particular case found under the node some_module.some_function.status). Clicking on it gives the information in the TRACE32 status status line \\some_app\some_module\some_func\status with type (auto STATUS), scope local, location stack.
Changing my script to read &varToBeSet=\\some_app\some_module\some_func\status instead of &varToBeSet=status, however, does not help much. In this case Lauterbach complains with no access to that symbol.
Is there a way, I can delay evaluation of the macro to some point where it is actually used instead of having it evaluated when it is defined?
Use quotes:
&varToBeSet="\\some_app\some_module\some_func\status"

Efficient way to pass gui variables to classes?

I'm using the program Maya to make a rather large project in python. I have numerous options that will be determined by a GUI and input by the user.
One example of an option is what dimensions to render at. However I did not make a GUI yet and am still in the testing faze.
What I ultimately want is a way to have variables be able to be looked up and used by various classes/methods within multiple modules. And also that there be a way that I can test all the code without having an actual GUI.
Should I directly pass all data to each method? My issue with this is if method foo relies on variable A, but method bar needs to call foo, it could get real annoying passing these variables to Foo from everywhere its called.
Another way I saw was passing all variables through to each class instance itself and using instance variables to access. But what if an option changes, then i'd have to put reload imports every time it runs.
For testing what I use now is a module that gets variables from a config file with the variables, and i import that module and use the instance variables throughout the script.
def __init__(self):
# Get and assign all instance variables.
options = config_section_map('Attrs', '%s\\ui_options.ini' %(data_path))
for k, v in options.items():
if v.lower() == 'none':
options[k] = None
self.check_all = int(options['check_all'])
self.control_group = options['control_group']
Does anyone have advice or can point me in the right direction dealing with getting/using ui variables?
If the options list is not overly long and won't change, you can simply set member variables in the class initializer, which makes the initialization easy for readers to understand:
class OptionData(object):
def __init___(self):
#set the options on startup
self.initial_path = "//network"
self.initial_name = "filename"
self.use_hdr = True
# ... etc
If you expect the initializations to change often you can split out the initial values into the constructor for the class:
class OptionData(object):
def __init___(self, path = "//network", name = "filename", hdr=True)
self.initial_path = path
self.initial_name = name
self.use_hdr = hdr
If you need to persist the data, you can fill out the class reading the cfg file as you're doing, or store it in some other way. Persisting makes things harder because you can't guarantee that the user won't open two Maya's at the same time, potentially changing the saved data in unpredictable ways. You can store per-file copies of the data using Maya's fileInfo.
In both of these cases I'd make the actual GUI take the data object (the OptionData or whatever you call yours) as an initializer. That way you can read and write the data from the GUI. Then have the actual functional code read the OptionData:
def perform_render(optiondata):
#.... etc
That way you can run a batch process without the gui at all and the functional code will be none the wiser. The GUI's only job is to be a custom editor for the data object and then to pass it on to the final function in a valid state.

Using Lua to define NPC behaviour in a C++ game engine

I'm working on a game engine in C++ using Lua for NPC behaviour. I ran into some problems during the design.
For everything that needs more than one frame for execution I wanted to use a linked list of processes (which are C++ classes). So this:
goto(point_a)
say("Oh dear, this lawn looks really scruffy!")
mowLawn()
would create a GotoProcess object, which would have a pointer to a SayProcess object, which would have a pointer to a MowLawnProcess object. These objects would be created instantly when the NPC is spawned, no further scripting needed.
The first of these objects will be updated each frame. When it's finished, it will be deleted and the next one will be used for updating.
I extended this model by a ParallelProcess which would contain multiple processes that are updated simultaneously.
I found some serious problems. Look at this example: I want a character to walk to point_a and then go berserk and just attack anybody who comes near. The script would look like that:
goto(point_a)
while true do
character = getNearestCharacterId()
attack(character)
end
That wouldn't work at all with my design. First of all, the character variable would be set at the beginning, when the character hasn't even started walking to point_a. Then, then script would continue adding AttackProcesses forever due to the while loop.
I could implement a WhileProcess for the loop and evaluate the script line by line. I doubt this would increase readability of the code though.
Is there another common approach I didn't think of to tackle this problem?
I think the approach you give loses a lot of the advantages of using a scripting language. It will break with conditionals as well as loops.
With coroutines all you really need to do is:
npc_behaviour = coroutine.create(
function()
goto(point_a)
coroutine.yield()
say("Oh dear, this lawn looks really scruffy!")
coroutine.yield()
mowLawn()
coroutine.yield()
end
)
goto, say and mowLawn return immediately but initiate the action in C++. Once C++ completes those actions it calls coroutine.resume(npc_behaviour)
To avoid all the yields you can hide them inside the goto etc. functions, or do what I do which is have a waitFor function like:
function waitFor(id)
while activeEvents[id] ~= nil do
coroutine.yield()
end
end
activeEvents is just a Lua table which keeps track of all the things which are currently in progress - so a goto will add an ID to the table when it starts, and remove it when it finishes, and then every time an action finishes, all coroutines are activated to check if the action they're waiting for is finished.
Have you looked at Finite State Machines ? If I were you I wouldn't use a linked list but a stack. I think the end result is the same.
stack:push(action:new(goto, character, point_a))
stack:push(action:new(say, character, "Oh dear, this lawn was stomped by a mammoth!"))
stack:push(action:new(mowLawn, character))
Executing the actions sequentially would give something like :
while stack.count > 0 do -- do all actions in the stack
action = stack:peek() -- gets the action on top of the stack
while action.over ~= true do -- continue action until it is done
action:execute() -- execute is what the action actually does
end
stack:pop() -- action over, remove it and proceed to next one
end
The goto and other functions would look like this :
function goto(action, character, point)
-- INSTANT MOVE YEAH
character.x = point.x
character.y = point.y
action.over = true -- set the overlying action to be over
end
function attack(action, character, target)
-- INSTANT DEATH WOOHOO
target.hp = 0
action.over = true -- attack is a punctual action
end
function berserk(action, character)
attack(action, character, getNearestCharacterId()) -- Call the underlying attack
action.over = false -- but don't set action as done !
end
So whenever you stack:push(action:new(berserk, character)) it will loop on attacking a different target every time.
I also made you a stack and action implementation in object lua here. Haven't tried it. May be bugged like hell. Good luck with your game !
I don't know the reasons behind you design, and there might be simpler / more idiomatic ways to it.
However, would writing a custom "loop" process that would somehow take a function as it's argument do the trick ?
goto(point_a)
your_loop(function ()
character = getNearestCharacterId()
attack(character)
end)
Since Lua has closures (see here in the manual), the function could be attached to your 'LoopProcess', and you call this same function at each frame. You would probably have to implement your LoopProcess so that that it's never removed from the process list ...
If you want your loop to be able to stop, it's a bit more complicated ; you would have to pass another function containing the test logic (and again, you LoopProcess would have to call this every frame, or something).
Hoping I understood your problem ...

How can a script retain its values through different script loading in Lua?

My current problem is that I have several enemies share the same A.I. script, and one other object that does something different. The function in the script is called AILogic. I want these enemies to move independently, but this is proving to be an issue. Here is what I've tried.
1) Calling dofile in the enemy's constructor, and then calling its script function in its Update function which happens in every game loop. The problem with this is that Lua just uses the script of the last enemy constructed, so all of the enemies are running the same script in the Update function. Thus, the object I described above that doesn't use the same script for it's A.I. is using the other enemies' script.
2) Calling dofile in the Update function, and then calling its script function immediately after. The problem with this is that dofile is called in every object's update function, so after the AILogic function runs and data for that script is updated, the whole thing just gets reset when dofile is called again for another enemy. My biggest question here is whether there is some way to retain the values in the script, even when I switch to running a different one.
I've read about function environments in Lua, but I'm not quite sure how to implement them correctly. Is this the right direction? Any advice is appreciated, thanks.
Edit: I've also considered creating a separate place to store that data rather than doing it in the Lua script.
Edit2: Added some sample code. (Just a test to get the functionality working).
-- Slime's Script
local count = 0;
function AILogic( Slime )
--Make the slime move in circles(err a square)
if count < 4 then
Slime:MoveDir( 0 );
elseif count < 8 then
Slime:MoveDir( 2 );
elseif count < 12 then
Slime:MoveDir( 1 );
elseif count < 16 then
Slime:MoveDir( 3 );
else
count = 0;
end
count = count + 1;
end
The lua interpreter runs each line as its own chunk which means that locals have line scope, so the example code can't be run as-is. It either needs to be run all at once (no line breaks), without locals, or run in a do ... end block.
As to the question in the OP. If you want to share the exact same function (that is the same function at runtime) then the function needs to take the data as arguments. If, however, you are ok with using the same code but different (runtime) functions than you can use closures to hold the local/individual data.
local function make_counter()
local count = 0
return function ()
local c = count
count = count + 1
return c
end
end
c1 = make_counter()
c2 = make_counter()
c3 = make_counter()
print(c1())
print(c1())
print(c1())
print(c1())
print(c2())
print(c3())
print(c2())
print(c3())
print(c2())
print(c3())
Alternatively, you could play with the environment of the function each time it is called, but that will only work correctly for some cases (depends on what the internals of the function are).
The canonical reference for this is link text. Explaining this briefly we'll work off the following code from the site:
a = 1
local newgt = {} -- create new environment
setmetatable(newgt, {__index = _G})
setfenv(1, newgt) -- set it
The first line sets up the (global) variable "a". You can view this as setting default values for your code. (Keep in mind that in Lua all variables are global unless you declare them with "local".)
The next line creates a table that will be your new environment. It is local to the function/chunk you're executing in so it won't be trashed by anything else that runs now or later.
The third line is the beginnings of the magic. To understand it you're going to have to understand metamethods In essence, however, you're using Lua's metamagic to ensure that any global names that aren't defined in your soon-to-be function environment get resolved in the context of your old global environment. Basically it means if you use a name that's not in your function environment, Lua will automagically hunt in the global environment you used to have to find the name. (In a word: inheritance.)
The fourth line is where you get what you're looking for. Setfenv(1,...) means that this changes the environment for your current function. (You could use 2 for the calling function, 3 for the calling function's caller, etc. on up the line.) The second parameter is the table you just set up, complete with inheritance of the old behaviour. Your function is now executing in a new global environment. It has all the names and values of the old environment handy (including functions and that global variable "a" you put in). If, however, you WRITE to a name it will not overwrite the global state. It will overwrite your local copy of it.
Consider the following subsequent code:
a = 10
b = 20
What you have done now is made your function environment table look like this:
{a = 10, b=20}
Your "global" environment, in short, contains two variables only: a (value 10) and b (value 20). When you access "a" later you'll get your local copy with 10 -- the old global value stored in your metatable is shadowed now and is still set to 1 -- and if you access "b" you'll get 20, despite the original global state likely not even having a variable "b" to access. And you'll still be able to access all the functions, etc. you've defined before this point as well.
Edited to add test code to debug OP's problem.
I put the following code into "junk.lua":
a = 1
local newgt = {}
setmetatable(newgt, {__index = _G})
setfenv(1, newgt)
print(a)
a = 10
print(a)
print(newgt)
The output of it is as follows:
$ lua junk.lua
1
10
table: 0x976d040
This is using Lua 5.1.4. What is the output you're seeing?