AddExit('north', 32)
That looks cooll. actually I'd prefer that. I"m not sure though
how to make AddExit use self by default. what determines how
that's going to be looked up, since it'll be in the room table?
On 10/25/2012 2:01 AM, Rob Hoelz wrote:
Here's the guideline I use for developing a scripting interface for
anything: just write some example scripts. Don't worry about how you're
going to do it just yet; just write some "play" scripts that will define
what your scripting API will feel like. After writing a few examples
and working
out things you thought were a good idea but now you don't like, you can
start actually making them work. For example, you have this script for
a room object:
self:AddExit('north', 32)
That's completely doable. Since you're working on a script that is
unique to a particular object, though, some people might prefer this:
AddExit('north', 32)
It's completely up to you! Think about what you want your scripting
layer to look like, then come back and we can help make that a reality. =)
-Rob
On 10/24/12 5:47 PM, Littlefield, Tyler wrote:
Hello:
The loading and execution of the objects is done for all objects.
Basically here's how this works, or at least how I see it working.
When objects are currently loaded, their script is executed. The
script is just stored on a property on the object so I can edit it
with an in-game editor.
So, if the script is on a room for example or an NPC, I'd like to do
something like: self:AddExit("north", 32) or something. Events are the
same way:
self:AddEvent("OnEnter", onEnter)
I have a rather outdated but functional copy of my work at:
http://code.google.com/p/aspenmud.
I'd just like to clean up scripting and make it work a lot better, but
I don't have a very great knowledge of Lua to do so, so I'm looking
for any advice on how to do so. Mainly I'm trying to make the
scripting side more OO-like, and I'd like to know if the execution
method that I had in a couple emails back is what is recommended for
sandboxing each object. I think here sandboxing is the wrong word, but
it sort of gives it it's own environment to work in, so that if I have
say, two onEnter functions on two different rooms, there won't be name
collisions.
On 10/24/2012 8:07 AM, Rob Hoelz wrote:
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.
--
Take care,
Ty
http://tds-solutions.net
The aspen project: a barebones light-weight mud engine:
http://code.google.com/p/aspenmud
He that will not reason is a bigot; he that cannot reason is a fool; he that dares not reason is a slave.
|