26 Nov, 2009, David Haley wrote in the 61st comment:
Votes: 0
When you have a pointer to a pointer, you need to dereference it once to get a pointer, and then you can dereference using ->.

Note, though, that you can also just store the pointer directly instead of using the whole CHAR_DATA** business – and then get a CHAR_DATA* out.
27 Nov, 2009, JohnnyStarr wrote in the 62nd comment:
Votes: 0
Yes, that is much better thank you.

David Haley said:
You could do the above, yes, although you would have to use ., not :. You would add a hook to the metatable for the "newindex" event, which detects assignment to a field that does not exist. Then you would look up the field that is trying to be assigned, and do something appropriate with it.


How is this done exactly?
Is this hook written in Lua or C?
27 Nov, 2009, Davion wrote in the 63rd comment:
Votes: 0
It's playing with pointers, Johnny! In this case, you'd simply just use

(*ch)->name;


You're trying to access ->name from a p2p instead of from the pointer to the CHAR_DATA struct.
27 Nov, 2009, JohnnyStarr wrote in the 64th comment:
Votes: 0
Davion said:
It's playing with pointers, Johnny! In this case, you'd simply just use

(*ch)->name;


You're trying to access ->name from a p2p instead of from the pointer to the CHAR_DATA struct.


Nice, I don't know why I didn't think of that first.
Using the parentheses it dereferences the pointer, just like:
@@                                                   
@@ch->name <=> (*ch).name
@@


EDIT: changed syntax because using '.' makes syntax black? weird.
27 Nov, 2009, Runter wrote in the 65th comment:
Votes: 0
Just thought I'd mention that your pointer to pointer dereferencing example could also be written as

(*(*ch)).name;


Which I think is pretty much obvious, but important to realize. -> amounts to a lexical macro for C.
27 Nov, 2009, David Haley wrote in the 66th comment:
Votes: 0
JohnnyStarr said:
David Haley said:
You could do the above, yes, although you would have to use ., not :. You would add a hook to the metatable for the "newindex" event, which detects assignment to a field that does not exist. Then you would look up the field that is trying to be assigned, and do something appropriate with it.


How is this done exactly?
Is this hook written in Lua or C?

It's up to you. You already create the metatable for actor objects somewhere (load_char_lua is your function). Currently, you have a bunch of functions in charlib – well, really, just 'send'/CHL_send at the moment. You need to add __newindex. See also the Lua manual section on metatables and look for the 'newindex' function to see what parameters you should expect. __newindex is called when you try to assign something; __index is called when you try to read a field. (It's actually more complicated in general for tables, but for user data this is the basic story.) So, you need to implement __newindex and __index to be able to handle reads and writes.
27 Nov, 2009, JohnnyStarr wrote in the 67th comment:
Votes: 0
So, I would write __newindex in C right?
This way, when you write:

ch.level = 35     – calls __newindex in C
if ch.level == 10 – calls __index in C


Am I on the right track with this?
27 Nov, 2009, kiasyn wrote in the 68th comment:
Votes: 0
correct
27 Nov, 2009, JohnnyStarr wrote in the 69th comment:
Votes: 0
@kiasyn
Thanks for your help as well.
29 Nov, 2009, JohnnyStarr wrote in the 70th comment:
Votes: 0
I've gotten __newindex to work great with my charlib metatable.
Now I'm writing __index to "get" the value, this is what I've written so far:

static int CHL_index( lua_State *L )
{
CHAR_DATA *ch = L_getchar(L);
char *field;
field = str_dup( luaL_checkstring(L, 2));

if (!str_cmp(field, "name"))
lua_pushstring(L, ch->name);

return 1;
}


/* registry for charlib_m (metatable) */
static const struct luaL_reg charlib_m [] = {
{"send", CHL_send},
{"__newindex", CHL_newindex},
{"__index", CHL_index},
{NULL, NULL}
};


However, I'm getting a null lua error.
Now, after thinking about it, if I'm writing my own __index, then in a way, isn't that Overriding Lua's __index method?
If so, then it's no wonder. Should I be writing __index in Lua? Can you override methods like this in Lua?
30 Nov, 2009, JohnnyStarr wrote in the 71st comment:
Votes: 0
Nevermind, I get it now :)

All you would have to do is write your own routine, if it's a property, send the value, if it's a function, send the function.
Duh!
30 Nov, 2009, David Haley wrote in the 72nd comment:
Votes: 0
Note that you only want to return '1' if you actually are returning something from the function; if it's not recognized you should return 0 (or push a nil and return 1, or something).

Lua's indexing behavior is given exactly in the manual section on metatables:

function gettable_event (table, key)
local h
if type(table) == "table" then
local v = rawget(table, key)
if v ~= nil then return v end
h = metatable(table).__index
if h == nil then return nil end
else
h = metatable(table).__index
if h == nil then
error()
end
end
if type(h) == "function" then
return (h(table, key)) – call the handler
else return h[key] – or repeat operation on it
end
end


Note that 'metatable(obj)' is used as shorthand for: getmetatable(obj) or {}
and see also the documentation for the function 'getmetat....

Basically, Lua always does the above checks when indexing an object. Whether or not things are looked at in C or in Lua depends on your setup, because you have have several layers of checking if you have several metatables. We're wandering into fairly advanced usage of metatables, though, and it can get pretty confusing if you're not careful to (perhaps only mentally) diagram the exact sequence of steps taken to look up a value. A nice thing about Lua is that the exact process is completely and unambiguously documented in the manual, even if it does mean occasionally deciphering functions as the above.
03 Dec, 2009, JohnnyStarr wrote in the 73rd comment:
Votes: 0
Is there a better way of getting a string from Lua than having to use str_dup() ?
Nick uses:
const char * name = luaL_optstring (L, 1, "self");

However, his use doesn't exactly work with what I'm trying to do.
I just want to grab strings sent from Lua scripts to compare in my __index / __newindex methods, however the only practical way
I've found is to copy them with str_dup then use free_string when I'm done.

This may just be a matter of preference, or this could actually be poor design. Any thoughts?
BTW, is Nick Gammon still around? I haven't seen too many recent posts from him.
03 Dec, 2009, David Haley wrote in the 74th comment:
Votes: 0
Why does his not work?

The standard thing to do is to use lua_tostring, which gives you a const char* directly into the Lua space. You are not supposed to keep this string lying around for longer than it exists on the Lua stack. This is particularly important when you are looking at an argument to a C function for example. But, if you're not going to look at the string for longer than the lifetime of the C function call, you're fine. You do not need to copy and then free them.

Maybe if you described why that doesn't work for you, we can figure out how to better design this. I'm not sure at the moment if this is poor design, preference, or something else.

Nick Gammon is extremely active on his site. If you (or I) point him toward an interesting topic here, he usually stops by and comments if he has something to say. I don't know to what extent he follows this forum in general, though.
03 Dec, 2009, kiasyn wrote in the 75th comment:
Votes: 0
In my code i have:

LUA_FUNCTION( LCharacter::__index ) {
CHAR_DATA *ch = CHECK_CHARACTER( L, 1 );
const char *field = luaL_checkstring( L, 2 );

// …
}


which hasn't given me any trouble.
03 Dec, 2009, JohnnyStarr wrote in the 76th comment:
Votes: 0
What I didn't realize is that I was making the mistake of passing the lua_tostring() as a char*:

static int CHL_goTo( lua_State *L )
{
CHAR_DATA *ch = L_getchar(L);
const char *argument = lua_tostring(L, 2);
do_goto(ch, (char*)argument);
return 0;
}


I guess what I overlooked is that sending argument as const char* wouldn't do because
the do_* functions expect a char* as "*argument". I suppose it would be best to duplicate
the argument in this case because most of the do_* functions modify the passed argument.
The above example works, but I think it would be dangerous because you are altering a string on the Lua stack right?
03 Dec, 2009, David Haley wrote in the 77th comment:
Votes: 0
Oh. Well, you reallyreally don't want to modify the string that lives in the Lua stack space.

If your do_func's require char*, then you have no choice: you must copy it and then free it.

Some time ago, I patched up SmaugFUSS so that all do_func's take const char* argument. I think that that is a superior solution on many levels.
04 Dec, 2009, JohnnyStarr wrote in the 78th comment:
Votes: 0
David Haley said:
Some time ago, I patched up SmaugFUSS so that all do_func's take const char* argument. I think that that is a superior solution on many levels.

I was thinking the same thing.

I am now facing garbage collection. In a Lua book I picked up, it has an example of including __gc into
your metatable, but I'm still having to figure out when our how to use it.
My current implementation for mobscripting sends in three arguments (actor, target, room) this makes
it very flexible. However, my current system's events are immediate only. Once a script ends, so do the
passed arguments.
Do the userdata objects have to be freed explicitly?
I'm looking into co routines, but that's yet another new thing to learn and my head
kind of hurts :tongue:
04 Dec, 2009, David Haley wrote in the 79th comment:
Votes: 0
Well. This is a complicated topic…

Forgive me if I repeat the potentially obvious, but everything that is allocated must be eventually freed. You obviously cannot free something once you have lost your handle to it – that is a memory leak. You do not want to access a handle after freeing it – that is an invalid memory access.

This means you need to manage two things:

1. Freeing memory early enough, before losing the handle.
2. Freeing memory late enough, after all necessary accesses.

Or in other words, at just the right time :-)

The Lua userdatum is a normal Lua object that will eventually be collected. So, it will eventually fizzle and go away.

Do you need to capture the __gc event? Well, that depends …

When you create the userdatum (a GC'ed object) do you allocate anything else to put into it? I don't think you do: you just store the pointer. So there is no memory associated with the userdatum other than the userdatum itself (which Lua takes care of).

What about the CHAR_DATA* pointer? Well, presumably this is "owned" by C++, and C++ will eventually take care of freeing it. You probably really don't want to free it when the Lua object is collected, because (presumably!) C++ is still going to use it. Besides, you said that your events are immediate only, so userdata will be fizzling quite often whereas the C++ objects will be far more stable.

In my system, the C++ object and the Lua userdatum share the same lifespan, so I could arrange things differently if I felt like it.

Now you do have a tricky situation, a sticky wicket as some of my colleagues might say: what happens if you, somehow, store a userdatum in Lua, and keep it around after the C++ object has been deleted? Attempting ot use the actor stored in the Lua userdatum will cause great consternation most likely resulting in a crash. Bad Times. How you solve this is a complicated issue. This complexity is one reason why Nick likes the one-state-per-character approach: it obviates any problem of how you store and manage memory across application spaces.

What I do – as I describe on that Lua thread at Nick's in more detail – is to use an ID system such that to check if an actor still exists you need simply look up its (guaranteed unique) ID in a table, and you can avoid crashes by doing what is basically a null pointer check.



You would override __gc if your userdatum involved creating some extra memory. For example, you might want to create a C++ object and associate it with the userdatum for the life of the userdatum, and you would want this object to be destroyed as soon as the userdatum is collected. In this event you would override __gc on your userdatum.
04 Dec, 2009, JohnnyStarr wrote in the 80th comment:
Votes: 0
It seems as though I wouldn't ever have an issue with a Lua object conflicting with a valid C pointer, because
you cannot call a Lua "mobscript" without setting up the userdata first. So, the only thing I can imagine is say
the actor is a mob, and the target is our Player: what if we had a "disarm" trigger, when you disarm
the mob, it fires a trigger that calls a mobscript to do something interesting. If somehow we called that script after
the mob somehow was killed, it would send in a pointer to a dead mob right?

Is this scenario even plausible? Or are there other potential dangers? I will be the first to admit that I am not very experienced with event systems, so I may change the immediate event approach. However, most would argue that you should only make immediate events (Tyche's TITS comes to mind).

I do like the ID system, and I am considering using something like that just to be safe.
60.0/125