Expanding objects

29 views
Skip to first unread message

Starkiel

unread,
Mar 24, 2009, 6:53:40 PM3/24/09
to Evennia
I have Evennia running fine and has been playing around with adding
commands through gamesrc/commands which seems to work well. Now, I'm
curious about how one is supposed to expand objects and player objects
with new qualities.

For example, I want all new player objects to have a few more
persistent attributes set (could be for skill values, short
description, whatever).

So, I create a new python source file in gamesrc/parents and have the
player class inherit from the base/basicplayer object. I make the
appropriate changes in the settings file to make this my new player
object. So far so good. But how would I now actually expand on this
object?

Since I want an attribute which is actually saved between sessions, I
tried to use
self.set_attribute('myatrr',"somevalue") in my inherited class
definition, but this simply causes the whole login process to freeze,
without any player being created, nor any error message or traceback
in the log.

Obviously I'm not going about it in the right way, any help?
.
Starkiel

Greg

unread,
Mar 26, 2009, 10:15:52 AM3/26/09
to Evennia
It sounds like you're most of the way there, you just may not be
setting the attribute correctly.

Assuming that you're extending BasicPlayer, you'll want to look at
evennia.src.script_parents.basicplayer. More specifically, at_pre_login
(). There's a good example of the way to do this there. You don't want
to modify this class directly, but that should give you a good idea of
how to do this correctly.

If you are indeed going about it this way and you've still got
problems, send over your new player class to the list or to me
directly and we'll work through it.

Sorry for the delayed response, job hunting and finishing up school
has me very busy!

Greg

Starkiel

unread,
Mar 26, 2009, 2:39:55 PM3/26/09
to Evennia
Thanks for the reply. I have (I think) followed a similar structure as
in at_post_login(), but it does not work.

If I do just

class Character(BasicPlayer):
pobject = self.source_obj
pobject.set_attribute('atest','test')

the system locks up.

If I try to go with subclassing the at_post_login function, it does
not freeze up, but also no attribute is set on the player ...

class Character(BasicPlayer):

def at_post_login(self,session):
super(Character,self).at_post_login(session)

pobject = self.source_obj

logger.log_infomsg("In at_post_login")
if not pobject.has_attribute(sdesc):
pobject.set_attribute('sdesc', "test")
pobject.set_attribute('ldesc','test')
if pobject.has_attribute('sdesc'): logger.log_infomsg("has
sdesc")
if pobject.has_attribute('ldesc'): logger.log_infomsg("has
ldesc")


Kindly,
Starkiel

Starkiel

unread,
Mar 27, 2009, 5:29:44 PM3/27/09
to Evennia
Seems to have figured it out on my own. :)

Noticed a simple typo in my code, in the check for if the attribute
was already set (sdesc instead of "sdesc"), and this was probably the
actual reason things goofed up. On that note it's still rather strange
that no traceback at all shows if there is an error at this point,
also when running the server in interactive mode ... one is not used
to python code being so uninformative.

At any rate, am I to take it, these two functions pre/post_login are
indeed the points to use for adding attributes to a custom player
object?

... Further, there seems to be a bug with the @set command; @set
me=sdesc: returns "SDESC cleared", but ex me clearly shows it is still
there. I'm not very used to mux though, so maybe there is a more
literal command. I haven't looked into it further but the underlying
set_flag(False) and clear_attribute methods are working as they should
if called directly without using the @set command.

Anyway, back to tinkering ... :)
.
Starkiel

Greg Taylor

unread,
Mar 29, 2009, 1:45:13 PM3/29/09
to eve...@googlegroups.com
Sorry for the delay,

I'll try to take a look at this tonight or tomorrow. I'm going to be
really spotty over the next few days due to a convention, but rest
assured that I'll answer things as quickly as I can.

Errors/exceptions should be showing in interactive mode, as well as
in-game by the person causing the error. This only happens when there
are exceptions, otherwise a more simple error message will be shown in
the server stdout/logfile or in-game.

pre/post_login are functions that are triggered every single time a
character logs in. If all you're wanting to do is set an attribute,
it's best to either set them at player creation (I can add an
at_player_created() event function), or have whatever system that uses
the attributes set them if it notices their absence (probably the most
robust solution).

It looks like this was accidentally made to mirror Penn's behavior
rather than MUX's. This should be an easy fix that I can address
shortly.

Thanks for the questions/feedback, this kind of stuff is very helpful
for codebase development.

Greg
--
Greg Taylor
Clemson University, Class of 2009
Cell: (864) 888-7964
http://gc-taylor.com

Greg

unread,
Mar 29, 2009, 8:55:27 PM3/29/09
to Evennia
OK, here's an update. Hopefully I've addressed everything in your
previous message, let me know if this stuff doesn't work for you.

> At any rate, am I to take it, these two functions pre/post_login are
> indeed the points to use for adding attributes to a custom player
> object?

This is addressed by revision 511. basicplayer.py now has
at_player_creation().

> ... Further, there seems to be a bug with the @set command; @set
> me=sdesc: returns "SDESC cleared", but ex me clearly shows it is still
> there. I'm not very used to mux though, so maybe there is a more
> literal command. I haven't looked into it further but the underlying
> set_flag(False) and clear_attribute methods are working as they should
> if called directly without using the @set command.

This should be resolved now.

Thanks again,
Greg

Starkiel

unread,
Apr 10, 2009, 4:20:24 AM4/10/09
to Evennia
Hmm ... I cannot get at_player_creation() to work...

For example, I test this in my custom player class:

def at_player_creation(self):
pobject = self.scripted_obj
logger.log_infomsg('in player creation')
pobject.emit_to("In creation...")
pobject.set_attribute('sdesc', 'a normal person')

This plain fails without any tracebacks and no logging occurs. Overall
it still
seems that any errors in these functions just causes them to die
silently without any tracebacks. It must be caught and silenced
somewhere.
The equivalent works if I put it in at_post_login(session) instead.
.
Starkiel

Greg

unread,
Apr 12, 2009, 4:44:12 PM4/12/09
to Evennia
I wasn't able to reproduce the failing part (it behaved as expected),
but I do see the silent failure problem and will need to try to figure
out where this is being caught. I probably have a careless 'except:'
statement somewhere instead of being more specific.

If you want to send me your entire new player parent file, I'll take a
look at it in more detail.

Starkiel

unread,
Apr 13, 2009, 9:33:37 AM4/13/09
to Evennia
Looking at the character behaviour further, it seems the problem does
not extend to normal player objects, but only to Player #1, for which
at_player_creation does not appear to work.



Another related issue is with parenting the THING class.

Using the below re-definition of the thing parent, @create an object,
then immediately do
examine <object name>
I find that the "sdesc" quality is nowhere to be seen. Now, do 'look
<object>' and redo the examine. Suddenly the sdesc quality has
appeared and will be there from now on. I haven't been able to find
out why this is. It's maybe more of a quirk, but it might hide some
other weird behavior somewhere. Added this as an issue to the issue
tracker, mainly in order to try it out. :)

.
Starkiel



-----------
from game.gamesrc.parents.base.basicobject import BasicObject

class BasicObject(BasicObject):
def __init__(self, source_obj, *args, **kwargs):
super(BasicObject,self).__init__(source_obj, *args, **kwargs)
name = self.scripted_obj.get_name
(fullname=False,show_dbref=False, show_flags=False)
self.scripted_obj.set_attribute('sdesc', str(name))

def class_factory(source_obj):
"""
This method is called any script you retrieve (via the
scripthandler). It
creates an instance of the class and returns it transparently.

source_obj: (Object) A reference to the object being scripted (the
child).
"""
return BasicObject(source_obj)

Greg Taylor

unread,
Apr 13, 2009, 10:15:57 AM4/13/09
to eve...@googlegroups.com
The reason you're having this problem with scdesc and regular objects
is that the class instance is lazily loaded. It won't be loaded until
actually used (in this case, at_desc is what warranted loading the
class). If you want to do something when an object is created, we can
add an at_object_creation() method to BasicObject that is triggered
when the object is loaded.

Because of the way these parent classes are instantiated, you pretty
much never want to much with __init__. It's kind of conceptually
weird, but if you look at scripthandler, it should start making sense.

As far as #1, he is created the first time the game is started, I
believe. Something different is probably be done from normal character
creation.

Hope that helps,
Greg

Starkiel

unread,
Apr 14, 2009, 5:59:01 AM4/14/09
to Evennia
I know about the lazy loading, but I still don't understand why "look"
causes the sdesc attribute to load when "examine" on the object does
not. I also haven't modified the look routine at all (yet) to include
the sdesc.

at_object_creation() sounds like a good idea though.

The #1 object will be the natural primary test character for future
admins/devs (of course), so it should ideally be identical to how all
objects work I think.
.
Starkuel

Greg Taylor

unread,
Apr 14, 2009, 7:13:06 AM4/14/09
to eve...@googlegroups.com
Because look calls the script parent's at_desc() function, which
causes it to be lazily loaded. examine does not call anything
script-related and therefore does not cause the parent to be lazily
loaded. examine is supposed to be the guaranteed, always working type
deal that doesn't depend on anything else. It doesn't (and probably
will never) reply on a script parent to be loaded since it's so
critical.

Greg

Starkiel

unread,
Apr 14, 2009, 1:30:01 PM4/14/09
to Evennia
I see your point about examine being stand-alone, but it is not
intuitive that the basic examine command should *not* be able to get
all the information it can from an object whenever that information is
requested.

... Could there not simply be a try statement around an attempt to
call the script parent on the examined object (thus attempting it to
force it to load). If this fails, the exception is silently abandoned
and the system works the way it does now, without loading anything?
.
Starkiel

Greg Taylor

unread,
Apr 14, 2009, 3:43:49 PM4/14/09
to eve...@googlegroups.com
The examine command gets all of the information on the object. I think
there's just some confusion here as to the way you should be doing
what you're trying to.

If you want to set an attribute at the time the object is created,
you'll need to do it within at_object_creation(). __init__ is not
something you should really ever override on the
BasicPlayer/BasicObject classes. __init__ only hits when the
scriptlink is first established for the object. If you want the
attribute to be there from the beginning, override the
at_object_creation() that I'll be adding.

I don't think this has anything to do with examine, it seems like this
is just a mixup of the best way to set attributes on object creation.

Starkiel

unread,
Apr 14, 2009, 5:24:07 PM4/14/09
to Evennia
Okidoki, that makes sense then. :)
.
Starkiel

Greg

unread,
Apr 17, 2009, 1:38:13 AM4/17/09
to Evennia
I don't know if you saw, but I added an at_object_creation() method to
BasicObject for this kind of thing. That should be what you're looking
for.
Reply all
Reply to author
Forward
0 new messages