lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On 10/24/12 3:59 PM, Littlefield, Tyler wrote:
> On 10/24/2012 1:38 AM, Rob Hoelz wrote:
>> Responses inline.
>> Hello:
> Thanks. To your first question, I was a bit unclear there. When I load
> an object, that's how I create a sandbox of sorts (so there aren't
> name collisions). I just put it through that execute method.
So each object has its own sandbox? Or just event objects?  I'm still
not clear.
>> As for the making things OO, I'd like to bind the c++ methods so that
>> they can be called with OO. So rather than what I have now, where I
>> have to call player.send(ch, "hello world!") I"d like to be able to
>> do player:send("Hello world.")
> I am curious what you'd do differently. As I said, I'm new to this
> whole thing, and revamping the scripting engine is kind of important
> before I get to far. Any advice is appreciated.
Well, let's take a step back.  What I would do depends on the project
itself, and I know next to nothing about yours.  I know so far that
you're adding scripting to a MUD, and you want to be able to fire and handle
events.  Would you mind going into more detail about how you see this
system working?
>
>> On 10/23/12 10:32 PM, Littlefield, Tyler wrote:
>>> Hello all:
>>> I've been working on a mud for a while, and my scripting engine is
>>> rather primative. basically a mud is just a multi-user text-based
>>> game, so it can be considered along the same lines as a game engine.
>>>
>>> I'd really like to revamp my scripting system before it gets more
>>> complicated than it is already. I'm not really sure how to do a couple
>>> of things though.
>>>
>>> First, triggers are obviously important. Currently I have events in
>>> game that just fire when an action is performed, so I can extend these
>>> to hit Lua.
>>> I'm thinking each object will just do something like:
>>> AddTrigger("give", onGive)
>>> This will just bind the onGive function/callback into an event that
>>> will be triggered when this happens. is that a decent idea? Every
>>> object that is loaded gets it's code executed in a virtual table of
>>> sorts. It looks something like this:
>>> void Script::Execute(Entity* obj, const std::string &code)
>>> {
>>>    lua_State* state = Script::GetState();
>>>    int ret = 0;
>>>    World* world = World::GetPtr();
>>>
>>>    if (!luaL_loadbuffer(state, code.c_str(), code.length(),
>>> "execution"))   // chunk is at -1
>>>      {
>>> //we need to create the metatable and store it in the registry:
>>>        lua_pushinteger(state, obj->GetOnum());
>>>        lua_newtable(state); // create shadow environment table at -1
>>>        lua_settable(state, LUA_REGISTRYINDEX);
>>> //now we get the table back again:
>>>        lua_pushinteger(state, obj->GetOnum());
>>>        lua_gettable(state, LUA_REGISTRYINDEX);
>>>        ObjectToStack(state, obj);
>>>        lua_setfield(state, -2, "this");
>>>        lua_getfield(state, LUA_REGISTRYINDEX, "meta"); //our metatable
>>> is at -1
>>>        lua_setmetatable(state, -2); //set table and pop
>>>
>>>        lua_setfenv(state, -2); //sets the environment
>>>        ret = lua_pcall(state, 0, 0, 0);
>>>        if (ret)
>>>          {
>>>            world->WriteLog(lua_tostring(state, -1), SCRIPT, "script");
>>>            lua_pop(state, 1);
>>>          }
>>>      }
>>> }
>>> Is this recommended? The idea was to keep objects from having naming
>>> collisions. For example if I had a function named foo on a sword and a
>>> player. Would this also be something to use when loading global
>>> scripts?
>> I'm not 100% on what this code is supposed to do; is it registering new
>> event callbacks, or is it invoking the callbacks for an event?
>>> Second, I'd really like to objify everything. For example in order to
>>> send a message to a player currently, I have to do:
>>> player.send(mob, "hello world!")
>>> How hard would it be to attach ehese in classes somehow, so I just
>>> call self:send("hello world!" or whatever?
>>> Right now my registration is done in a table:
>>> BOOL InitPlayerScript(Script* s)
>>> {
>>>    lua_State* lstate = s->GetState();
>>>    luaL_newmetatable(lstate, "player");
>>>    lua_pushstring(lstate, "__index");
>>>    lua_pushvalue(lstate, -2);
>>>    lua_settable(lstate, -3);
>>>    luaL_openlib(lstate, "player", player_table, 0);
>>> ...
>>> }
>>> static const struct luaL_reg player_table [] =
>>>    {"GetTitle", SCR_GetTitle},
>>>    {"SetTitle", SCR_SetTitle},
>>> ...
>>>    {NULL, NULL}
>>> };
>>> int SCR_GetTitle(lua_State* l)
>>> {
>>>    UserData* udata = NULL;
>>>
>>>    if (lua_gettop(l) != 1)
>>>      {
>>>        SCR_Error(l, "Invalid number of arguments to \'GetTitle\'.");
>>>        return 0;
>>>      }
>>>
>>>    udata = (UserData*)lua_touserdata(l, -1);
>>>    if (!IsPlayer(l, udata))
>>>      {
>>>        return 0;
>>>      }
>>>
>>>    lua_pushlstring(l, ((Player*)udata->ptr)->GetTitle().c_str(),
>>> ((Player*)udata->ptr)->GetTitle().length());
>>>    return 1;
>>> }
>>> int SCR_SetTitle(lua_State* l)
>>> {
>>>    const char* title = NULL;
>>>    UserData* udata = NULL;
>>>
>>>    if (lua_gettop(l) != 2)
>>>      {
>>>        SCR_Error(l, "Invalid number of arguments to \'SetTitle\'.");
>>>        return 0;
>>>      }
>>>
>>>    title = lua_tostring(l, -1);
>>>    if (!title)
>>>      {
>>>        SCR_Error(l, "Argument 2 to \'SetTitle\' must be a string.");
>>>        return 0;
>>>      }
>>>
>>>    udata = (UserData*)lua_touserdata(l, -2);
>>>    if (!IsPlayer(l, udata))
>>>      {
>>>        return 0;
>>>      }
>>>
>>>    ((Player*)udata->ptr)->SetTitle(title);
>>>    return 0;
>>> }
>>> Can something like this be more OO like?
>> Which part do you want to be more OO? The Lua part? The C++ part?  Your
>> C++ code looks like it would work with OO-style Lua, although I would do
>> a few things differently (namely, if !IsPlayer, I would throw
>> an error).
>>> Finally, I'm curious how to go about setting up object properties. a
>>> lot of muds that have used lua (I was just looking at the Aard page)
>>> sets stuff up
>>> like ch for the calling player, self for the current object, then they
>>> allow for like ch.gold, ch.int etc. I'm curious how this works. I know
>>> about setting values on a table, but it seems that the table would
>>> have to call it's underlying c++ object's GetGold method to retrieve
>>> it.
>> What you could do is have an __index metamethod that returned the value
>> of the property as needed.  Here's an example in Lua; converting it to
>> C++ is left as an exercise for the reader. =)
>>
>>     local mt      = {}
>>     local object = setmetatable({}, mt)
>>     function mt:__index(key)
>>       if key == 'time' then
>>         return os.time()
>>       end
>>     end
>>     print(object.time)
>>> Thanks in advance, and sorry for all the questions.
>>>
>>
>
>