Monday, 31 January 2011

Loading issues fixed

well, so far as loading chapter headings and background images goes, anyway. Still a lot of cases need adding.

Next I want to do the shuffle code. there's two parts to this: shuffling the narratives in a scene (or items in a narrative, or options in a choice, etc, etc, etc) and then there's re-arranging the treeview to reflect the change.

Let's get test cases for the Scene, Narrative and the rest, first.

Saturday, 29 January 2011

A Test Case

SceneEdit, Boo. Test Case. Why isn't the image tag loading from XML?

        [Test]
        def load_background2():
                source = detab("""
                <scene name="GameStart" default="" desc="wibble wibble">
                 <narrative name="waking_up" desc="In which our hero ...">
                  <image path="data/images/foo.png" />
                  <image path="data/images/bar.png" />
                 </narrative>
                </scene>
                """)

                sr = StringReader(source)
                r = XmlReader.Create(sr)
                scene = Scene()
                scene.load(r)
/*
 *              make sure we have a narrative
 */
                Assert.AreEqual(1, scene.narratives.Count)
/*
 *              get the narrative, check the name
 */
                n as Narrative
                n = scene.narratives[0]
                Assert.AreEqual("waking_up", n.name)
/*
 *              now - it should have two narrative items attached
 */
                Assert.AreEqual(2, n.items.Count)


And that fails: there are zero items in the narrative. Also of interest is an error message in the test output saying "name image not handled". I missed that in the general output chatter when running the app itself.

A bit of grepping tracks that down to the Narrative class:

        def load(r as XmlReader):
                _name = gatt(r, "name")
                _desc = gatt(r, "desc")

                while r.Read():
                        if r.NodeType == XmlNodeType.Whitespace:
                                continue
                        if r.NodeType == XmlNodeType.EndElement:
                                if r.Name == "narrative":
                                        break
                                continue
                        if r.NodeType != XmlNodeType.Element:
                                print "unexpected node type: ${r.NodeType}"
                                break
                        if r.Name == "narrative":
                                break
                        if r.Name == "snippet":
                                sn = Snippet()
                                sn.load(r)
                                _items.Add(sn)
                                continue
                        print "name ${r.Name} not handled"


So I need to add a case to that loop for every tag I intend to read. Tedious, but at least I found it.

Incidentally, that's lousy O-O methodology. One of the basic ideas behind OO is that you have subclasses so you don't need to have ifs or switches like this. The trouble is that this kind of breaks down when you're reading text data.

The OO way to do it would be to have a factory method, typed as NarrativeItem that took the class name as a string and returned the appropriate item. You'd have a reader class specific to each tag and register them with the factory so it knew what objects mapped to what strings.

Really though, life's too short. Getting all that working and debugged is a task in its own right, and for something as minor as this, it just isn't worth it.

Of course, all that may change as the code evolves. For now though, we'll go with the old-fashioned approach.

Friday, 28 January 2011

Shuffling Along

OK, time to look at the shuffle problem. First of all the verb needs to change to "move", if only on the buttons. "Shuffle" takes up too much space. (That said, I'm going to need another row of buttons before I'm done, but that for later).

The thing that stops this being trivial is that we need to be able to shuffle anything from menu choices to narratives.

I think I need some more test cases...

Thursday, 27 January 2011

Shallow Bugs and Whoremaster

Well, there are that many bugs in this editing tool, if I hadn't doucmented the test suite as I went, I'd wonder if I ever tested it.

The thing is, short of some complicated and expensive software, there isn't a good way to repeatably test GUIs. (OK, it should be possible to do some tricks with NUnit and reflection, but I've never quite got that to work in practice).

Anyway, the theory is to put the application logic into a dll and test the hell out of that. The GUI code is to be as thin a wrapper around the dll as possible. But the GUI still needs testing - which is what I'm belatedly doing now, I suppose.

On the bright side, the bugs have generally been pretty superficial - which should be one payoff of the TDD phase. There shouldn't be any deep errors in the application logic, because I have tested the hell out of that.

On another note, I'm quite enjoying playing Whoremaster again. One of the drawbacks of developing a game is that somehow you never get to play it. You make changes and you test them, but somehow you stop playing for fun. Having had a break from the dev process, I'm starting to enjoy the game, and in doing so I#m starting to think about what I'd like to do to the source code.

I'm not about to break my sabbatical just yet but ... I'm starting to look forward to doing some work on the program again.

First Or Second Person

I keep alternating between wanting to write scenes in first and second person. So I thought I'd throw the question to the audience, as it were, and see what people think.

Both styles can be effective. The old Infocom style text adventures generally used second person narratives:
You are in a round room.

> PISS IN THE CORNER

Sorry, I don't understand "corner".

You are in a round room.

And that generally worked. The style was very much based on the pencil-and-paper role-playing games of the time, but you can tell a tale and get the player to identify with the protagonist. Of course you probably need to be a bit careful what words you put in the player's mouth, (and what thoughts you put in the players head!). Even then, games like Curses and Trinity play from the perspective of someone who definitely is not the player, and they still work very well.

Japanese style ADV games on the other hand tend to use first person, at least from the examples I can bring to mind. The dialog tends to be stream of consciousness from the MQ.

This is a very strange room I find myself in. It appears to be completely round.


It's all a bit confusing to me. They told me to take a piss in the corner, but there are no corners to piss in.


Maybe I could do it in the middle and claim the piss drained there. Maybe that would work. Or maybe they would see through my ruse and be angry with me.


It is a conundrum.
I think this possibly works better for ADV text. Second person seems a bit like constantly telling the player what to do. It's all right for descriptive text, as in Zork you have to say what happens to the player as the result of his choices. But then you get a lot more choice per text passage in Zork than you do in any ADV game.

Anyway, opinions anyone?

For example...

If there's no configuration set up, SceneEdit doesn't always default to the current folder. (actually, it should probably default to the one above on the assumption that it's been called from the tools sub folder.

If you edit the path and change it, the change is not reflected in the textbox

You can click +Narrative from the initial config screen and crash the tool - because the scene isn't set up as yet.

Dogfood, I tell you.

[edit]

Fixed them. Started a new scene, called it "waking up" hit tab ... and it crashed. This may take longer than I'd anticipated.

I think I'll just edit this post rather than spread the debug process over umpteen posts.

[edit]

Too many to log, all fairly simple. One that might take a bit more work: TreeView nodes aren't being set quite right. There's a nasty disorienting jump. Probably the result of a ham-handed fix to an earlier crash problem. (Scene needs to be a NarrativeItem - and I suspect Narrative will also need that distinction).

[edit]

No crash on narratives, but browsing for images doesn't use the game Resource folder as its root - which is the point of the config entry...

... the file browser doesn't do thumbnails for images - have to check the docs for that - I might be using it wrong ...

... and when I do find the image I need, the label in tree view is wrong...

[edit]

Save dialog uses the last image folder as default, which is wrong. Can fix that with two save dialog objects, perhaps. Seems wasteful, but should work.

On the bright side, it seems to be getting usable pretty quickly. There's hope yet :)

[edit]

Never did get around to making the shuffle buttons work...

[edit]

images and chapter headings don't appear to load. They save ok, but they don't appear in the loaded treeview. Let's review those test cases.

Also, specifying the XML file on the command line doesn't work

Wednesday, 26 January 2011

Time To Eat Dogfood

If you're familiar with the idea of the "dogfood test", the title will make sense. If not it probably sounds a bit weird.

In software, the dogfood test is "does the developer use his own tools and/or products?" If a maker of dogfood thinks their product really is healthy, they'll be quite happy to eat it themselves. If not, you're entitled to ask "so what's wrong with it?" Similarly, you should expect a software house to use its own tools.

Which is a pain right now, because I need to convert all the text so far. I've got this neat GUI tool to do that (and spent way to long writing it) but what I really want to do is fire up vi and hand edit the XML.

The thing about that is ... you can always tell when a developer doesn't use his own tools. If you use a program, you tend to find and fix the problems as they occur. Eventually it gets to be more than just functional. It gets to be smooth. If you don't use it, then you tend to leave the rough edges in place.

So, if I want other people to use SceneEdit, I guess I better use it myself.

I expect there are dog food manufacturers who don't much care for the taste of dog food, come to think of it.

GuiStage

I'm chipping away at this in tiny little chubks at the moment. I get just so far and my concentration seems to go. Never mind, we do waht we can.

Today's exercise is to write the GuiStage class. A while back I wrote about using a "Stage" class to abstract the game engine and let me test the adv engine. I have a TestStage which works and using it I have a lot of tests (many of which need updating - the XML format changed during the SceneEdit develoment)

Anyway, now I need a GuiStage class. This being Lua, there isn't an actual base class to work from, so I'm going to adapt the Test version.

--[[
 * A Stage is where a Narrator might enact a Scene. So that's the
 * metaphor - a Stage is the interface that the Narrator class uses
 * to interact with the user (or test harness).
 *
 * in this case, we're interacting with the game GUI. Yayy!
--]]
module(..., package.seeall)

GuiStage = GuiStage or {}
GuiStage.__index = GuiStage

--[[
 * Create the object. Not sure what data we need to store
--]]
function GuiStage:new()
    self = { }
    setmetatable(self, GuiStage)
    return self
end

--[[
 *
 * This sets the background image for the adv window.
 *
--]]
function GuiStage:image(file)
end

--[[
 * This displays a message box
--]]
function GuiStage:text(string)
end

--[[
 * This called when a choice is displayed, to test the display
 * The result will be apparent from the text elements following the choice
--]]
function GuiStage:choice_show(options)
end

--[[
 * This called when a the result of a choice is required
 *
 * What we'll do is pop the value off the front of the input queue
--]]
function GuiStage:choice_result(item)
end

--[[
 * background image: not sure why this is here -
 * or what the difference is with the image method.
--]]
function GuiStage:set_background(filepath)
end


That's what I have to work to. I'm a little nonplussed to find I wrote two methods to set the background image. That said the set_background one doesn't seem to be used anywhere - test or production code. I'm tempted to use the name for the other method ... but that leaves too much code to fix and too many possible bugs if I miss something.

Anyway, that's my worklist.

Tuesday, 25 January 2011

Finally!

At last, it's working. Or at least the introduction is - there are grat swathes still to write. The problem seems to have been with the event manager. I don't know what it was, but I ended up rewriting it using std::list.

Now, I can backtrack to test the XML format I was working on around Christmas, convert the story-so-far to XML, and then start to look at the lab screen again.

Monday, 24 January 2011

Back into C++

Been a bit slow on the Conemaster front; I've been working on a generalised event format for Otherworld. I won't go into details here. If you're interested, check out the thread on the otherworlds board.

Meanwhile, back to C++. That can't find from namespace message seems to be harmless. It blows up on script because there's an event loop iteration before any window is displayed and the framework expects to find something with a script() method. I should probably add a dummy function into startup.lua just to silence that.

So why are those damn buttons not working? Best guess is a bug in the C++ framework. Doing some debugging, a click on the new button generates an event with an ID of 800 - but that isn't the ID under which the button is registered.

So, I need to dig a little deeper. This is all still catch-up stuff from before summer, really. I've been assuming the C++ was sound and all the problems lay in Lualand. Clearly that was an optimistic assessment...

Oh well, if it was easy, it wouldn't be any fun :)

Wednesday, 19 January 2011

Lua and C++ - still

OK, one last chunter on this subject, and then it's high time I did some actual work.

Really, one thing that stands out from this is that I don't need to do much to the current setup. The prepare/run (I might call that init/run) approach works well for repeating events that need to be re-initialised. If the function isn't there it doesn't get called. The initial script doesn't have a namespace, but that's fixable, either by allowing a "" namespace meaning "look this up globally" or else by modding setup to use Setup or something similar. Or I could pass "_G" as a namespace, which would cause the lookup to use the global table.

I am a little worried that people will try and write functionality that runs when the chunk is executed, rather than when the functions it defines are executed. The problem there is that I'm not sure when a script/chunk will be executed, so the timing is undefined and subject to change.without notice. But writing the thing to execute when the script is parsed may well work for a lot of events. And of course, there's a pile of Lua that is supposed to work like that.

I guess I still don't have an entirely clear idea of how all this is going to work, despite writing way too many words on the subject.

Maybe the solution is to code some stuff up and see what happens. Getting ideas-on-paper is one thing, but this is turning into putting-off-work.

Tuesday, 18 January 2011

Lua and C++: Lost in the wilderness

That was a longer break than I intended. I blame job hunting, real life, and a certain amount of Fallout 3. But let's not dwell on that.

I said I got very confused about how Lua worked with C++. I started thinking things like "well, if a chunk returns a function, then I should be defining functions. So I'd write a lua script like this:

function greeter()
      log("greeter script begin")
      message("Welcome to Clonemaster")
end

... and then wonder why it didn't work. Of course, it doesn't work for the same reason as it wouldn't work in a Lua script: the function is never called. When I run the Lua chunk I define the function, but need to also call it to make it run. If I'd just added one line to it, it would have been fine:

function greeter()
      log("greeter script begin")
      message("Welcome to Clonemaster")
end

greeter()


That seems so obvious in retrospect, but at the time, it cause me major headaches.

The other thing was the fact that Whoremaster needed the script exit so the SDL event loop could run. This meant that some things didn't happen when you asked them to happen. Message noxes just queued up, and that was fine. But image changes didn't happen until the script returned. So if you had three different images to illustrate those queued text boxes, they all be shown at once, at the end, and only the last one would be seen. Likewise, menus never got drawn until the script returned.

Eventually, I figured this out, and decided that what I needed was to have a separate namespace for each script, and for each one to have "prepare" and "run" methods.

Example = Example or {}

local stage = 0

Example.prepare = function()
        // set up the class variables ready for the script to run
        stage = 0
end

Example.run = function()
        // set up the class variables ready for the script to run
        stage = stage + 1
        if stage == 1 then
                // do stuff up to the first change of scenerey
        elseif stage == 2 then
                // do stuff up to the second...
        // ...
        end
end


The prepare idea was partly because necno's scripts in WM had a prepare method, and partly because I needed something to reset events when they were triggered.

Actually, that's probably still a pretty good event template for Clonemaster. It's just that I'm using scripts in a lot of other ways too, so I think I need to be a bit more flexible in how I call them.


One possibility which occured to me some time ago: if I can factor the SDL event loop into a C++ function, I could call it from inside the script. That would simplify a lot of the Lua architecture. It was too big a change for WM; for Clonemaster ... I'm worried that I'd need multiple invocations until it was ready to return to the script, and that in that time, the user would find a way of triggering another script, resulting in multiple embedded event loops, and some very hard to find errors. I still am, and I'm not going to do it for that reason...

Need to think about this a bit more..

Thursday, 13 January 2011

Lua and C++: storing chuinks, functions, packages, modules

So: if we want to use a Lua chunk more than once, we need to keep track of where we can find it. Let's look at how functions work in Lua for a moment.

Normally, you define a lua function like this:

function foo()
    print "woof"
end

foo()


All fairly unremarkable. You can also create anonymous functions and assign them to variables:

foo = function()
        print "woof"
end

foo()


In actual fact, the two cases are identical. Just like in JavaScript/Actionscript (and probably a ton of other languages as well) if you write "foo()", the interpreter looks for a variable called "foo", checks to see if "foo"  contains a reference to a functions, and if it does, that function is called.

So, thinking about our C++ program, all we need to do is take that chunk and store it in  a global symbol. We can check that. First I want to split the loading and execution parts into their own funcs:

/*
 * load the string: the compiled code will be left in a "chunk"
 * (an anyonymous function) on the top of the stack
 */
int load(lua_State *L, string proggy)
{
        int rc = luaL_loadstring(L, proggy.c_str());
/*
 *      zero means success here
 */
        if(rc == 0) {
                return 0;
        }
/*
 *      report the error
 */
        cout    << "there was an error loading the script: <<"
                << lua_tostring(L, -1)
                << ">>"
                << endl
        ;
        return 1;
}

That's exactly the same code as before, just in its own func and with some extra comments and whitespace.

Similarly for the call part:

/*
 * call the function on top of the stack - bare minimum
 */
int call_top(lua_State *L)
{
        int rc;
/*
 *      run pcall: no args, no return, default handler
 */
        rc = lua_pcall(
                L,              // lua state
                0,              // number of arguments
                0,              // number of expected return values
                0               // error handler - use lua default
        );
/*
 *      a return of zero means everything worked OK
 */
        if(rc == 0) {
                return 0;
        }
/*
 *      the only other possible return (according to the docs) is one
 *      which means an error
 */
        cout    << "there was an error loading the script: <<"
                << lua_tostring(L, -1)
                << ">>"
                << endl
        ;
        return 1;
}

And then the main func gets a bit more manageable (and I can stop copying the include statements each time...)

int main()
{
        int rc;
        string prog = "print \"hello\"";
/*
 *      create a state for the lua interpreter
 */
        lua_State *L = lua_open();
/*
 *      set up the standard lua libraries
 */
        luaL_openlibs(L);
/*
 *      try and load the program - exit if it fails
 */
        if(load(L, prog) == 1) {
                return 0;
        }
/*
 *      call the chunk: it's on top of the stack
 */
        call_top(L);
/*
 *      shutdown the interpreter
 */
        lua_close(L);
        return 0;
}


Storing the chunk is easy:

/*
 * stores the function on top of the stack as global name
 * lua_setglobal pops a value from the stack, so the func will
 * no longer be there when this returns
 */
void save_chunk(lua_State *L, string name)
{
        lua_setglobal(L, name.c_str());
}


Looking it up again:

/*
 * stores the function on top of the stack as global name
 * lua_setglobal pops a value from the stack, so the func will
 * no longer be there when this returns
 */
void find_chunk(lua_State *L, string name)
{
        lua_getglobal(L, name.c_str());
}


It's fairly easy to see that these functions are just wrappers around the lua calls - and in fact they can be used to assign anything to a global name - whatever is on top of the stack. So normally I wouldn't bother with the functions, and I do so here purely for the sake of clearer explanations. (Hope it works).

Anyway:

int main()
{
        int rc;
        string prog = "print \"hello\"";
/*
 *      create a state for the lua interpreter
 */
        lua_State *L = lua_open();
/*
 *      set up the standard lua libraries
 */
        luaL_openlibs(L);
/*
 *      try and load the program - exit if it fails
 */
        if(load(L, prog) == 1) {
                return 0;
        }
/*
 *      chunk is on top of the stack - store it!
 */
        save_chunk(L, "hello");
/*
 *      lookup the chunk under global "hello" and then call it
 */
        for(int i = 0; i < 3; i++) {
/*
 *              need to find it before each call
 */
                find_chunk(L, "hello");
                call_top(L);
        }
/*
 *      shutdown the interpreter
 */
        lua_close(L);
        return 0;
}


And that now works as expected, printing "hello" three times. So we can parse a script and store itas a named function. But is that the best way to do things?


And this is where I started to get seriously confused...

Lua and C++: load and execute

OK. A couple of posts back I mentioned how luaL_dostring was mildly discouraged. I said I'd talk about that a bit more later. So let's do that.

The luaL_ functions are convenience functions in the Lua C API. There's nothing in them that is primitive: nothing in luaL_* that can't be done using a few calls to lua_* functions.

luaL_dostring is a case in point. The manual page is short and to the point.

int luaL_dostring (lua_State *L, const char *str); 
Loads and runs the given string. It is defined as the following macro:
     (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0)) 
It returns 0 if there are no errors or 1 in case of errors.
So the function basically does a load and and exec. That's not necessarily a bad thing, but you get some more options if you split load and exec. Specifically, you can load a big and complex lua script once, and then run it several times, without the overhead of parsing the string.

Of course, to do that you need to be able to fund the function once you've loaded it. luaL_loadstring is a convenience wrapper for lua_load (which is more complicated than most people will ever need), but you still need to look at lua_load to get the important datum:

Loads a Lua chunk. If there are no errors, lua_load pushes the compiled chunk as a Lua function on top of the stack
A "chunk" is what lua calls the compiled bytecode resulting from a load operation. As the manual says , the chunk is typed as a function. So to make it happen you need to call it. Usually with lua_pcall.  The "p" in pcall means "protected mode" which means that an error in the lua code can't crash the C++ program  Generally, you want all your calls to use protected mode.

So let's go back the simple hello program:

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

using namespace std;

#include <string>
#include <iostream>

int main()
{
        int rc;
        string prog = "print \"hello\"";
/*
 *      create a state for the lua interpretter
 */
        lua_State *L = lua_open();
/*
 *      set up the standard lua libraries
 */
        luaL_openlibs(L);
/*
 *      load the string: the compiled code will be left in a "chunk"
 *      (an anyonymous function) on the top of the stack
 */
        rc = luaL_loadstring(L, prog.c_str());
        if(rc == 1) {
                cout    << "there was an error loading the script: <<"
                        << lua_tostring(L, -1)
                        << ">>"
                        << endl
                ;
        }
/*
 *      call the chunk: it's on top of the stack
 */
        rc = lua_pcall(
                L,              // lua state
                0,              // number of arguments
                0,              // number of expected args
                0               // error handler - use lua default
        );

        lua_close(L);
        return 0;
}

 
And that works. So now I can write

        lua_pcall(L, 0, 0, 0);
        lua_pcall(L, 0, 0, 0);
        lua_pcall(L, 0, 0, 0);

And get "hello hello hello", right? Wrong. I get one "hello". The other two calls do nothing.

The problem is that the function has to be on top of the stack.The trouble is, to quote the manual:

All arguments and the function value are popped from the stack when the function is called
So by calling the chunk, we've lost it. It presumably still lives somewhere deep inside the luaState data, but I don't know any way to retrieve it.

So what we need to do is to make a note of where we can find it before we make the call....

Wednesday, 12 January 2011

Lua and C++, Part 2

OK, so: Having explained the Lua stack, we can now find out why the program is failing (I have a sneaking suspicion, but let's do this by the numbers).

This is the code:

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

using namespace std;

#include <string>
#include <iostream>

int main()
{
        string prog = "print \"hello\"";
        cout    << "prog = [["
                << prog
                << "]]"
                << endl
        ;

        lua_State *L = lua_open();

        int rc = luaL_dostring(L, prog.c_str());
        if(rc == 1) {
                cout    << "there was an error executing the script: [["
                        << lua_tostring(L, -1)
                        << "]]"
                        << endl
                ;      

        }

        lua_close(L);
        return 0;
}


Now when I say that lua_tostring(L, -1) takes the error string on top of the stack and returns it as a const char *, it hopefully makes sense. Compile and run...

I get this:

prog = [[print "hello"]]
there was an error executing the script: [[[string "print "hello""]:1: attempt to call global 'print' (a nil value)]]

First things first: I'd forgotten that Lua uses square brackets to delimit the offending Lua code. That makes my use if them confusing. Second thing... print undefined? Why can Lua find print in the interpreter and not when I call it?

The reason is quite simple. Creating a Lua state gets you an empty Lua interpretter. Nothing has been defined as yet - including the lua library functions. There C functions to load all the stand lua libs. Or this one to load them all at once:

        luaL_openlibs(L);

Add that in under lua_open and it works.


And after all that, I've forgotten where I was going with all this. Let me have a think about it...

About the Lua stack.

Lua communicates with C/C++ with the Lua Stack. If you're not familiar with the idea of stacks as data structures, there's a good wiki page on the subject.

Basically, the stack is an array. In lua, the convention is that low numbers are near the bottom of the stack, and high numbers near the top. So index 1 is always the bottom of the stack. Adding items to the stack is called pushing, since you're metaphorically pushing the stack down to make room for a new item. Similarly, removing an item from the top is called popping.

When Lua calls a function defined in C/C++, the stack consists of the function arguments provided in the Lua script, with the first argument being at index 1, and the Nth at index N. Each Lua-to-C[1] call gets a new stack, so you don't need to worry about what might have been left on the last one you saw. When the C function returns, the stack needs to contain any return values, with the first one being at index 1. (Yes, Lua can return more than one value). The last thing on the stack has to be the number of return values. Lua will work it out from there.

Going the other way, if C calls Lua, the first the function needs to be pushed on first, followed by the first argument, then the second and so on. When the Lua code returns, the return values are on the stack[2]. The stack used here belongs to the lua_State and may have other things on it. So you can't assume that return value 1 is at index 1 in the stack. (Lua doesn't believe in counting-from-zero BTW. It can be terribly confusing for C types like myself).

The only other thing we need to talk about is how to access stack entries. Let's consider lua_tostring. This function takes a value on the stack and returns it as a string (converting the value on the stack to a Lua string in the process, if you accidentally it an int, or something non-stringy). If you know the index in the stack, you can access it directly:

        string foo =  lua_tostring(L, 1);

will initialise foo with the string value at index one - the base of the stack. The trouble is, often you don't know the absolute index, but you do know where the value is relative to the top of the stack. In this case you can use a negative index, and Lua will count down from the stack top.

        string foo =  lua_tostring(L, -2);



That gets the second item from the top of the stack.

So, now we have all the bits to get at the error message in the previous post...

[1] C or C++ - writing C/C++ everywhere is getting to be a pain.

[2] It's not exactly the same going from Lua to C because lua_call/lua_pcall tells Lua how many return values it expects, so there's no need for a count. See the function documentation if you need full details.

Lua and C++

I'm not sure this is as complicated as I thought it was last night; I think I was too tired to think straight. Still, it does no harm to make a few notes on the subject.

So let's write a simple Lua script:

print "hello"

Put that in a file called "hello.lua" and run it with "lua hello.lua". It should print "hello" to the console.

So let's have a C++ program do that. First we need to include the Lua headers.

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}


That supplies definitions for the Lua functions and types. The 'extern "C"' bit tells the compiler that the Lua libraries are in C, not C++.

Then some C++ includes so we can use strings and stream I/O:

#include <string>
#include <iostream>


All standard stuff. A main function, with our lua program in a string:

int main()
{
        string prog = "print \"hello\"";
}

Had to escape the quotes, otherwise unremarkable.

Next - start a Lua state. I had trouble getting my head around this bit for some reason.

        lua_State *L = lua_open();

Clearly, it's starting a Lua session - so why "state"? Well, if you think about it, any running program has two parts to it. There's the code, which is the binary stuff in the .exe file, and then there's the program state, which is all the variables that tell the program what line number it's up to and so forth. So the Lua guys cleverly kept the state separate the code, which isn't always as easy as it sounds. And since we already have the code part included in the lua libraries, all we need is to keep track of the state, and we can do anything the lua command interpreter can do.

Hence lua_State. That *L pointer is effectively the lua interpreter program, embedded in C++ and ready for  the next line of input.

The state also keeps track of any variables and functions you define. This means that if you run "x = 54321" in one call, and "print x" in another, you get the value 54321 printed to the console. And if you create another lua_State with another lua_open() call, you get a whole new dataspace with completely unrelated variables,

So, you can see why I had trouble getting my head around that. There's a lot more to that one line than initially meets the eye.

Next, load and run the string. The simplest way to do that is like this:


        int rc = luaL_dostring(L, prog.c_str());

luaL_dostring is a convenience method which loads and runs the string all in one. The documentation mildly discourages you from using it, and we'll see why in due course. But it's by far the fastest way to get this program running.

Just for the sake of form, we'll close down the lua_State before we exit. If probably doesn't matter in this case, but if we were creating and destroying lots of lua states, this would stop us leaking memory

        lua_close(L);

Put it all together:

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

using namespace std;

#include <string>
#include <iostream>

int main()
{
        string prog = "print \"hello\"";

        lua_State *L = lua_open();

        int rc = luaL_dostring(L, prog.c_str());

        lua_close(L);
        return 0;
}


And it does nothing. What went wrong? We can print out the value of prog to make sure that's the same as in our lua script

        cout    << "prog = [["
                << prog
                << "]]"
                << endl
        ;


And that's correct. How about checking the return code from luaL_dostring? The manual tells us that a return of 1 indicates an error:

        int rc = luaL_dostring(L, prog.c_str());
        if(rc == 1) {
                cout << "there was an error executing the script" << endl;
        }

And apparently we have an error. We need to find out what it was. Digging through the documentation a bit we find that if there is an error (either loading or executing) then the error message is pushed onto the stack.

Actually, talking about the Lua stack is probably worth a post on its own...

[edit]

Kudos.

Tuesday, 11 January 2011

"namespace not found" -- part 2

Ran this sucker under the debugger for a bit. The namespace not found error comes, not from GameMenu.lua as I'd supposed, but from startup,lua - the first script called.

startup has the job of setting up the script environment for everything that follows. So if startup goes wrong, it can have knock-on effects for everything else. Here's the code:

log("package.path = " .. package.path)

require "Game"

--
-- This script is defined in config.xml as the one that gets called
-- when the game first starts up.
--
-- It needs to do four things:
--
--      1 load the window definitions
--      2 load the game data (girls, locations, items, etc)
--      3 set up the background picture
--      4 push the first window onto the stack
--
--
-- There's no reason it can't run at load time
-- just make sure it returns false at the end so
-- the game engine doesn't look for a script() function to run
--

--
-- 2: game data -- todo
--
local game = Game:new()

--
-- preload window definitions
--
game:load_windows(
        "GameMenu.xml",
        "Intro.xml",
        "Chapter.xml",
        "Main.xml",
        "Cloning.xml"
)

--
-- set the background image for the game
--
game:set_background("background")

--
-- 4: initial window
--

show("game_menu")
--show("cloning")

return game


So here we see a game namespace being used. We're requiring "Game" which makes me wonder if this isn't  capitalisation issue. But it gets as far as loading the game windows - otherwise the game menu couldn't display.

Also interesting is that it loads twice, going by the gamelog. That initial log appears two times, which suggests the file is being parsed twice. It could be that there's an identical log statement in another file of course.

Overall though - I think I need to get my thoughts in order on how Lua embedding works, and how the game currently tries to do that. What I have at the moment is probably broken on all sorts of levels.

But I think that's a post for tomorrow. It feels like this has been a long day, somehow.

"namespace not found"

OK. Let's look at those buttons. Gamelog.txt says "Error: namespace not found: 'game'"

So what does that mean? It's a terrible thing when you can't remember how your own code works, To start, let's look at the Resource/Interface folder. In there, there is a file called GameMenu.xml that defines the initial menu screen. The first line in that file says

<Screen ScreenName="game_menu" ScriptFile="GameMenu.lua">

Also of interest in that file:

     <TextButton Name    = "Profile"
        Image          = "blank"
        XPos        = "600"
        YPos        = "200"
        Width        = "150"
        Height        = "38"
        Transparency    = "true"
        Scale        = "true"
        Hidden        = "false"
        Handler         = "new_button"
    >


 
Together that tells us that a function called game_menu.new_button will get called when the Profile (Profile!?!) button is clicked. Having the button named "Profile" is a cut-and-paste error. Sadly, fixing it doesn't help. Anyway: When the *ahem* "New" button is clicked, we exepct game_menu.new_button to be called, which should be defined in GameMenu.lua.

We fined GameMenu.lua. in Resources/Scripts:

log("game menu handler script: init")

game_menu = {}

function game_menu.refresh()
    log("refresh called from script")
    return true
end

function game_menu.process(init_flag)
    log("process called from script")
    return true
end

function game_menu.new_button()
    log("new button clicked")
--
--    pop the menu screen
--
    pop_window()
--
--    show the intro screen
--
    --show("Cloning")
    show("intro")
--
--    show more than one and they stack, last in first displayed
--    if you want to pass arguments to a call, pass them as a table
--
    Game.chapter = "Waking Up Is Hard To Do"
    show("chapter")
    return true
end

return 1


This was one of the earlier Lua handlers I wrote and it shows. It doesn't use Lua's module mechanism for instance. It does define the needed function so that's ok. But the only reference to a "game" namespace is the "game.chapter" reference. And I'm fairly certain that the error message in question is one of mine, not one from Lua. So back to square one. Time to look at the C++ source.

Progress

OK, after some googling about, I found a decent newbie instructions on how to set up SDL_image for MinGW.

Works like a charm:




Must do a new version of that. "Whoremaster in space" was the initial concept, but things have moved on a bit since then.

[edit]

Also, committed that to svn so I don't need to do all this again in a fortnight's time. And I updated the "proper" svn checkout, rather than the backup version that for some strange reason was the closest to working I could find.

And the buttons don't work. but one thing at a time, hey?
Loading image
Click anywhere to cancel
Image unavailable