lag and performance

122 views
Skip to first unread message

Ll Kk

unread,
Dec 12, 2017, 9:42:04 PM12/12/17
to Evennia
How can I get max performance and response time ? I think my mobs activities are slowing things down.

- CPU and RAM, of course
- setting a process to high priority ?

- is there an Evennia setting to slow down the ticker somehow , or something similar that may result in a performance (response time to commands) boost ?

Griatch Art

unread,
Dec 13, 2017, 2:05:51 AM12/13/17
to Evennia
How have you implemented your mobs? Using Scripts or the Tickerhandler? How many operations are they performing and in what way?

You should start by running your game with the profiler (see docs) to try to see just where the bottleneck is. If you make the profile output file available I could take a look at it.
.
Griatch

Ll Kk

unread,
Dec 13, 2017, 11:00:55 AM12/13/17
to Evennia

I am using the Tickerhander. They alternate between "patrol" mode and "attack" mode. Both modes are similar, except attack includes an attack, and patrol includes a move.
Both modes cycle through a bunch of stuff :
- heal a little bit
- percent chance to use a special ability
- if_bleeding, then chance to take damage
- if_poisoned, then chance to take damage
- (a few more conditions similar to this)

They seem to handle this ok. The slow down seems to be caused mainly by each character(player) having a script on them which is bodyfunctions, controlling their healing, if_bleeding, etc.

The character scripts fire every 8 seconds, ( while the mobs patrol pace and attack pace ranges from 6-12 )

I've noticed a significant improvement when I only have 3 characters and 3 scripts, rather than 17 characters and scripts.

Is there a way to stop the bodyfunctions scripts while a character is logged out ? ... and then turn it on while they are logged in ?

I'm not sure how to run my game with the profiler, but I could nut it out.

Ll Kk

unread,
Dec 15, 2017, 5:02:18 PM12/15/17
to Evennia

or, how can I get a single scripts to work on multiple characters.

This search_object seems to only find one character with an alias characterbody, but there are multiple in the game. How to get the search to return multiple, so this single scripts can affect multiple characters ?

    def at_repeat(self):

    characterbody = search_object('characterbody')[0]

        if characterbody.db.tomatoeaten >= 5:
            etc etc etc

Nicholas Matlaga

unread,
Dec 15, 2017, 5:11:21 PM12/15/17
to Evennia
search_object already returns a list; Is it possible you only have one object called "characterbody"? In a stock Evennia instance, I created three objects, all with an alias of "apple", and search_object returns all three.
However, I would perhaps use the typeclass argument anyway, perhaps. You can use evennia.ObjectDB.objects.filter(db_typeclass_path='whatever.your.custom.typeclass').

Ll Kk

unread,
Dec 16, 2017, 1:15:17 AM12/16/17
to Evennia
I'm not doing something right. This isn't working on multiple characters with alias "body". Only seems to work on one specific character:

    def at_script_creation(self):
        self.key = "bodyfunction"
        self.desc = "various timed events to a body"
        self.interval = 8  # seconds
        self.start_delay = True  # wait self.interval until first call
        #self.persistent = True

    def at_repeat(self):

        body = search_object('body')[0]

        if body.db.tomatoeaten >= 5:

            if body.db.invisible:
            if random.random() < 0.10:
                    animalvisstring = "\n%s |Yfarts |nand becomes visible !" % (body.key)
                    body.location.msg_contents(animalvisstring)

                   
                   (rest of that file...)

How would I use evennia.ObjectDB.objects.filter(db_typeclass_path='whatever.your.custom.typeclass') ??

Like this ?

    def at_repeat(self):

        body = search_object('evennia.ObjectDB.objects.filter(db_typeclass_path='mygame\typeclasses.characters.Character')')[0]

        if body.db.tomatoeaten >= 5:
                (etc etc)

Also, what does the [0] at the end of
body = search_object('body')[0] mean ?

Griatch Art

unread,
Dec 18, 2017, 9:48:09 AM12/18/17
to Evennia
The tickerhandler is optimized for working on multiple objects in sync. Most likely the issue is that you are doing unnecessary things each cycle. For example, there is often no reason to update things like poison and healing every tick. You could pre-calculate all this and only retrieve the value when someone actively looks for it.
For example, let's say your poison will drop HP by 1 every 10 seconds. You then know how long you have until the char is dead - let's say it will take ten minutes. That's the only time you really need to keep track of - unless something happens to cure the poison (and abort the countdown) you have a poison ticker which will fire with the death notification in ten minutes. The only time you need to actually know what the HP is, is when the player actively looks at the HP - and then you can easily calculate it on the fly by checking the current time and calculating what the current value must be. This is a very efficient way to handle things.

There is one case where this on-demand calculation won't work, and that is with things that should pop up without player input. That is, if you have a message popping up "You loose 1 HP to poison" (or has a health bar). For that you do need to calculate the HP on the tick. But a lot of these things are useless to put on a ticker and much better to calculate only when the information is actually needed.

As for search_object, it returns a list. The `[0]` at the end means that you are using index 0 of that list - that is, only using the first match. So that's why you only get one Character all the time.
.
Griatch

Ll Kk

unread,
Dec 19, 2017, 8:10:12 PM12/19/17
to Evennia
Thanks again for your help !

:D

and Merry Christmas to everyone here, too.

Ll Kk

unread,
Dec 22, 2017, 3:02:13 PM12/22/17
to Evennia

As for search_object, it returns a list. The `[0]` at the end means that you are using index 0 of that list - that is, only using the first match. So that's why you only get one Character all the time.

How can I get it to use all returned "ischar" matches ? Change the [0] ?




On Tuesday, December 19, 2017 at 1:48:09 AM UTC+11, Griatch Art wrote:

Nicholas Matlaga

unread,
Dec 22, 2017, 3:22:00 PM12/22/17
to Evennia
You'll get a list back - completely omit the [0] to get that list.

Ll Kk

unread,
Dec 22, 2017, 4:47:19 PM12/22/17
to Evennia
I've got this script running on a separate object :
All characters have an alias "body".

class BodyFunctions(DefaultScript):
    """
    This class defines the script itself
    """

    def at_script_creation(self):
        self.key = "bodyfunctions"
        self.desc = "various timed events to a character"

        self.interval = 8  # seconds
        self.start_delay = True  # wait self.interval until first call
        #self.persistent = True

    def at_repeat(self):

    body = search_object('body')

        if body.db.tomatoeaten >= 5:
                                        etc etc etc

but the server is returning the error :

2017-12-23T08:47:03+1100 [-] [EE] Script bodyfunctions(#240) of type 'BodyFunctions': at_repeat() error ''str' object has no attribute 'tomatoeaten''

I just want one script running that will find all characters and run the processes on them (if bleeding, if poisoned, etc).

Is it because the script is running on a separate object ? I don't know why it's not finding the characters properly.

Any ideas ?

Ll Kk

unread,
Dec 31, 2017, 4:36:12 AM12/31/17
to Evennia
Is there a way to get a single script, running on object A, to affect object B,C,D,E, etc.
I am trying to get a script to work on all returns of an alias (body), like this :


    def at_script_creation(self):
        self.key = "bodyfunctions"
        self.desc = "various timed events to a character"

        self.interval = 8  # seconds
        self.start_delay = True  # wait self.interval until first call
        #self.persistent = True

    def at_repeat(self):

    body = search_object('body')

        if body.db.tomatoeaten >= 5:
                                        etc etc etc

and the advice I am following is to remove the [0] from the search_object function, so the script will affect all "body" returns, but it's not working.

Error :

2017-12-23T08:47:03+1100 [-] [EE] Script bodyfunctions(#240) of type 'BodyFunctions': at_repeat() error ''str' object has no attribute 'tomatoeaten''

So, I'm still using a script-per-character(body) to control bleeding, farting, etc, . . . when I'd like to see if I can get a performance boost from having just one script reach out to all bodies, you know what I mean ?

Any ideas ?

Griatch Art

unread,
Dec 31, 2017, 7:21:46 AM12/31/17
to Evennia
If you are unsure what a function does, test it in `evennia shell` or using `@py` in game. For example, do `@py evennia.search_object("body") and see what you get back. You should get a QuerySet which you can loop over. so the way to use this is

for body in search_object("body"):
    # do stuff

What happens if you do search_object("body")[0] is that you take the first matching body only - if it exists, if none exists, this will lead to an error.

The error you get though, the 2017-12-23T08:47:03+1100 [-] [EE] Script bodyfunctions(#240) of type 'BodyFunctions': at_repeat() error ''str' object has no attribute 'tomatoeaten'' is different though, that suggests that you have overridden the .db handler somehow with a string, since normally .db.tomatoeaten should return either the value or None if not defined. To test this, do this loop manually so you can debug it:

@py for body in evennia.search_object("body"): print type(body.db)

The type() should be the dbhandler, not str, if it it's wrong you need to examine your code to figure out where things have gone wrong. Put print statements in your code, figure out when values change and why.
.
Griatch


Ll Kk

unread,
Dec 31, 2017, 11:43:49 AM12/31/17
to Evennia
Wow this is great. Yes, I got it working, with this :
One script now affects all characters (body).
---------------------

class BodyScriptNew(DefaultScript):

    """
    This class defines the script itself
    """

    def at_script_creation(self):
        self.key = "bodyfunctionsall"

        self.desc = "various timed events to a character"
        self.interval = 8  # seconds
        self.start_delay = True  # wait self.interval until first call
        #self.persistent = True

    def at_repeat(self):

        for body in search_object("body"):

            if body.db.tomatoeaten >= 5:
                               etc etc etc
-----------------

THANKS for the help !
Reply all
Reply to author
Forward
0 new messages